From bcc1b1df3d323c55888873ed934315d2c92505c4 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 13 May 2026 21:57:13 -0400 Subject: [PATCH] Add support for IPv6 hostnames in addrparse Fixes https://github.com/staktrace/mailparse/issues/137 The colon character in IPv6 hostnames normally gets interpreted as a group delimeter, but group names cannot contain '@' characters. So if we encounter a colon and previously encountered an '@' then don't treat the colon as a group delimiter and just treat it as part of the address. --- src/addrparse.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/addrparse.rs b/src/addrparse.rs index ff564ec..23120e9 100644 --- a/src/addrparse.rs +++ b/src/addrparse.rs @@ -579,7 +579,7 @@ fn addrparse_inner( // Technically not valid, but occurs in real-world corpus, so handle it gracefully state = AddrParseState::Initial; addr = None; - } else if c == ':' { + } else if c == ':' && !addr.as_ref().map_or(false, |s| s.contains('@')) { if in_group { return Err(MailParseError::Generic( "Found unexpected nested group", @@ -1101,4 +1101,44 @@ mod tests { ]) ); } + + #[test] + fn parse_ip_hostnames() { + assert_eq!( + addrparse("").unwrap(), + MailAddrList(vec![MailAddr::Single( + SingleInfo::new(None, "test@example.org".to_string()).unwrap() + )]) + ); + assert_eq!( + addrparse("").unwrap(), + MailAddrList(vec![MailAddr::Single( + SingleInfo::new(None, "test@[192.0.2.0]".to_string()).unwrap() + )]) + ); + assert_eq!( + addrparse("").unwrap(), + MailAddrList(vec![MailAddr::Single( + SingleInfo::new(None, "test@[IPv6:2001:db8::1]".to_string()).unwrap() + )]) + ); + assert_eq!( + addrparse("test@example.org").unwrap(), + MailAddrList(vec![MailAddr::Single( + SingleInfo::new(None, "test@example.org".to_string()).unwrap() + )]) + ); + assert_eq!( + addrparse("test@[192.0.2.0]").unwrap(), + MailAddrList(vec![MailAddr::Single( + SingleInfo::new(None, "test@[192.0.2.0]".to_string()).unwrap() + )]) + ); + assert_eq!( + addrparse("test@[IPv6:2001:db8::1]").unwrap(), + MailAddrList(vec![MailAddr::Single( + SingleInfo::new(None, "test@[IPv6:2001:db8::1]".to_string()).unwrap() + )]) + ); + } }