pub fn parse_address_list(input: &str) -> Vec<Address>Expand description
Parses a comma-separated address list, respecting quoted strings, angle brackets, parenthesized comments, and RFC 5322 group syntax (RFC 5322 Section 3.4).
This is the liberal address parser used internally to interpret
inbound From/To/Cc/Bcc/Reply-To/Sender headers, exposed
publicly so consumers can apply the same Postel-compliant parsing to
other “be liberal in what you accept” inputs — for example,
user-typed recipient strings in a compose form, or addresses already
extracted from an IMAP ENVELOPE response.
§Behavior
- Returns
Vec<Address>with one entry per recognized mailbox. The parser never errors: malformed segments are best-effort-recovered or silently dropped (Postel’s law, RFC 1122 Section 1.2.2). - Group syntax (
display-name ":" [group-list] ";") is unwrapped and member addresses are flattened into the result. Empty groups (e.g.,undisclosed-recipients:;) contribute no addresses. - Parenthesized comments (RFC 5322 Section 3.2.2) may appear in addr-spec CFWS contexts and can contain commas, angle brackets, and other address-significant characters; these are not treated as separators.
- Domain-literals (
[192.0.2.1],[IPv6:...]) are preserved intact per RFC 5321 Section 4.1.3. - Display names are normalized: quoted-strings are unescaped, CFWS comments are stripped, and RFC 2047 encoded-words are decoded only in unquoted phrase spans (RFC 2047 Section 5 rule (3)).
§No outgoing validation
The returned Address records are constructed via
Address::new_unchecked and may contain syntax that is technically
non-conformant but still meaningful — exactly what is needed when
receiving from the network. They have not been validated against
the strict outgoing-mail rules in RFC 5322 Section 3.4.
If you are about to send mail — or otherwise need to enforce strict
validation — pass each result through Address::new or
Address::with_name afterwards. Those constructors apply the same
rules the message builder uses and will reject malformed input at
construction time rather than at send time.
§Input expectations
The input is a single, already-decoded address-list string.
This function does not perform RFC 5322 Section 2.2.3 header
unfolding, charset detection, or transfer-encoding decoding.
Feeding it raw header bytes with CRLF folds, 8-bit content from
unknown charsets, or quoted-printable sequences will produce wrong
results — use parse_email for raw message
bytes, and use this function for text that has already crossed the
wire/semantic boundary (user input in a UTF-8 terminal, a decoded
header value, etc.).
§Example
use daaki_message::{parse_address_list, Address};
let raw = r#""Doe, Jane" <jane@example.com>, alice@example.com"#;
let addrs = parse_address_list(raw);
assert_eq!(addrs.len(), 2);
assert_eq!(addrs[0].name.as_deref(), Some("Doe, Jane"));
assert_eq!(addrs[0].email, "jane@example.com");
assert_eq!(addrs[1].name, None);
assert_eq!(addrs[1].email, "alice@example.com");
// For outgoing mail, re-validate each result through the strict
// constructors so malformed input is rejected before send time.
let validated: Result<Vec<Address>, _> = addrs
.into_iter()
.map(|a| match a.name {
Some(name) => Address::with_name(name, a.email),
None => Address::new(a.email),
})
.collect();
assert!(validated.is_ok());§References
- RFC 5322 Section 3.4 (address specification)
- RFC 5322 Section 3.2.2 (comments)
- RFC 5322 Section 3.2.4 (quoted-string)
- RFC 5322 Section 3.2.5 (phrase / display-name)
- RFC 5321 Section 4.1.3 (domain-literal)
- RFC 2047 Section 5 (encoded-words in phrase context)
- RFC 1122 Section 1.2.2 (robustness principle)