Companion helper (ADR 0006) that reports structural, per-recipient
facts about the recipients in the positional to of a
mailto: URL --- the comma-separated addr-spec list before the
? (RFC 6068 section 2). Recipients carried in to/cc/
bcc hfields are RFC 5322 address-lists and are deliberately
out of scope; only the positional list is analysed.
get_mailto_recipients(
url,
url_standard = "rfc3986",
scheme_policy = c("infer", "require"),
scheme_acceptance = c("general", "web"),
smtp_wire = FALSE
)A data.frame (always, including for length-1 or all-empty
input) with one row per positional-to recipient and columns:
urlthe source URL the recipient came from.
recipient_index1-based index of the recipient within that URL's positional list.
mailto_local_part_formRFC 6068 local-part form:
"dot-atom-text", "quoted-string", "invalid", or
"indeterminate".
mailto_domain_formRFC 6068 domain form:
"ascii-dot-atom-text", "idna2008-domain",
"bracketed-domain", "invalid", or
"indeterminate".
smtp_mailbox_rhs_syntax_formRFC 5321 mailbox RHS form,
independent of the mailto grammar and of DNS: "domain",
"address-literal", "invalid", or
"indeterminate".
public_suffix_knownTRUE/FALSE whether the
domain's public suffix is known to the PSL (non-validating);
NA when the RHS is not a domain form.
smtp_domain_wire_form(opt-in) "ascii-domain",
"a-label-domain", "u-label-domain",
"address-literal", or "unavailable".
smtp_envelope_wire_mode(opt-in) "ascii",
"smtputf8", or "unavailable".
smtp_envelope_address_requires_smtputf8(opt-in) logical;
NA when no wire projection could be made.
smtp_local_part_length_ok(opt-in) logical, serialized
local-part at most 64 octets; NA when unavailable.
smtp_direct_forward_path_fits(opt-in) logical, the octet
length of "<" + Mailbox + ">" is at most 256; NA when
unavailable. The familiar 254 is the RFC 3696 EID 1690 derivation of
this path limit, not a standalone production.
A character vector of URLs. Non-mailto: URLs (and, under
scheme_acceptance = "web", all mailto: URLs, which the web
allowlist does not accept) contribute no rows.
Standard profile passed to the general parser. A
mailto: path is opaque, so this does not affect the classification;
it defaults to "rfc3986" because the general parser requires a
selector.
Controls whether scheme-less, host-shaped input is
accepted (an input-acceptance axis, distinct from protocol_handling,
which only controls how the scheme is presented, and from url_standard,
which controls interpretation). Defaults to "infer".
"infer": (Default) Fabricate http:// for scheme-less host-shaped
input (e.g. example.com parses as http://example.com), a
browser-omnibox-style affordance. This is the historical behavior.
"require": Reject scheme-less input — a scheme-less host-shaped
value becomes parse_status = "error" rather than gaining a fabricated
scheme. Use this for a strict, pure-parser posture. Note this governs
only bare host input; scheme-relative //host input is governed
separately by scheme_relative_handling.
Which scheme tokens may enter parsing (a
scheme-acceptance axis, distinct from scheme_policy, which governs
scheme-less input, and from url_standard, which governs interpretation).
Defaults to "web".
"web": (Default) Only the curated web-scheme allowlist
(http/https/ftp/ftps/file) is admitted; a scheme-bearing input
outside it is parse_status = "error". This is the historical,
byte-for-byte compatible behavior.
"general": Admit any syntactically valid scheme token and parse
opaque (mailto:x), non-special (foo://host), and RFC-generic URLs.
Requires an explicit url_standard ("rfc3986" or "whatwg"), which
decides the interpretation; general with url_standard = NULL is an
error. Non-special / opaque hosts receive no www-stripping, no domain/TLD
derivation, and are never run through the IDNA/punycode helpers.
A non-special scheme with no // is an opaque path: it has no
authority, so host, user, port and the domain/tld columns are
all NA and the entire remainder is the path (query/fragment are
still split off). This includes mailto: — the recipient's @ never
re-triggers authority parsing. To decompose a mailto: recipient, use
the accessors (get_host() / get_domain() / get_user(), ADR 0012 D7)
or get_mailto_recipients(); those deliberately return a recipient's
parts where this table presents NA, because a recipient domain is
extraction metadata, not the URL's authority.
Note that file: is admitted under both values, including the default.
A file: URL denotes local-filesystem access, and one with a non-empty
host (file://server/share/x) is a UNC path on Windows, so dereferencing
it reaches a remote SMB share. rurl parses file: URLs; it never opens
them. Restricting schemes before anything dereferences them is the
caller's job — see SECURITY.md.
Logical; when TRUE, compute the opt-in SMTP
wire-projection columns (see the corresponding section). Defaults to
FALSE.
These are selected structural facts, not
a conformance oracle and never a validator. A recipient's classification
never turns a parse into an error, and the absence of an invalid
value does not imply the address is deliverable or fully RFC-conformant.
No DNS resolution or deliverability check is performed.
Set smtp_wire = TRUE to
additionally compute the SMTP transport facts that require an actual
serialized wire projection of the address (octet-length limits per RFC 5321
section 4.5.3.1, and the SMTPUTF8 envelope mode per RFC 6531/6530). These
are octet facts on the UTF-8 wire bytes, distinct from the syntax
classifications above and from DNS. When smtp_wire = FALSE (the
default) the five smtp_* wire columns are still present but carry
the "unavailable"/NA sentinel; the same sentinel is used for
a recipient whose address cannot be projected (an invalid mailbox).
The positional list is tokenized on the
raw (still percent-encoded) source before decoding, so an encoded
comma (%2C) is never a recipient separator and an encoded quote or
bracket (%22, %5B/%5D) still protects a raw comma;
each field is then percent-decoded exactly once and classified.
Each fact names the grammar it was judged against. The left of the
addr-spec is classified as an RFC 6068 local-part and,
independently, the right is classified both as RFC 6068 mailto domain
vocabulary and as an SMTP (RFC 5321) mailbox right-hand side --- these are
distinct grammars, so no single column spans them. Public-suffix knowledge is
reported separately and is explicitly non-validating: a known suffix
is not mailbox validity.
get_url_diagnostics, safe_parse_url
get_mailto_recipients("mailto:[email protected]",
scheme_acceptance = "general")
get_mailto_recipients(
"mailto:[email protected],\"b,c\"@example.org",
scheme_acceptance = "general"
)
# opt-in SMTP wire-projection facts
get_mailto_recipients("mailto:[email protected]",
scheme_acceptance = "general", smtp_wire = TRUE)
Run the code above in your browser using DataLab