Skip to main content

parse_address_list

Function parse_address_list 

Source
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)