{"schema_version":"1.0","publisher":"Primitive SDKs","canonical_url":"https://test.abhinandan.one/node-sdk-parsing-email/node-sdk-address-parsing","markdown_url":"https://test.abhinandan.one/node-sdk-parsing-email/node-sdk-address-parsing.md","article":{"id":"fedae995-faa8-4234-b59c-62b3269402cb","article_slug":"node-sdk-address-parsing","parent_article_slug":"node-sdk-parsing-email","parent_article_title":"Parsing Raw Email (.eml)","kind":"reference","published_at":"2026-08-11T18:54:58.809606+00:00","keywords":["parseFromHeader","parseFromHeaderLoose","ParseFromHeaderResult","ParseFromHeaderFailureReason","ValidatedAddress","ParsedAddress"],"meta_description":"parseFromHeader strictly validates a single RFC 5322 address for authorization gates, while parseFromHeaderLoose returns a best-effort address plus display name for display-only use.","og_image_url":null,"source_file_paths":["sdk-node/src/parser/address-parser.ts"],"recording_id":null,"replayable":false,"task_name":"Raw MIME Address Parsing (parser/address)","category":"Node.js SDK","summary":null,"description":"Reference for parseFromHeader and parseFromHeaderLoose, the two RFC 5322 address parsers in @primitivedotdev/sdk/parser that extract a single validated address from a From/Sender header.","content_kind":"repo_page","content_markdown":"## What the address parsers do\n\nTwo address parsers ship under `@primitivedotdev/sdk/parser`: `parseFromHeader`, a strict RFC 5322 parser meant for authorization decisions, and `parseFromHeaderLoose`, a lenient parser meant for display-only call sites. Both operate on a raw header string (e.g. the `From` or `Sender` header value) and are implemented in `sdk-node/src/parser/address-parser.ts`.\n\n<Warning>\n\nNever use `parseFromHeaderLoose` for permission gates or any decision that grants access. Its recovered display name can silently absorb a second address or garbage tokens. Use `parseFromHeader` for anything security-bearing.\n\n</Warning>\n\n## parseFromHeader\n\nStrictly parses a header for security-bearing contexts: allowlist gates, permission grants, [domain-anchored sender trust](node-sdk-email-authenticity) anchors, and similar decisions where the address itself is the thing being trusted.\n\n```typescript\nimport { parseFromHeader } from \"@primitivedotdev/sdk/parser\";\n\nconst result = parseFromHeader('\"Alice\" <alice@example.com>');\n\nif (result.ok) {\n  console.log(result.value.address); // \"alice@example.com\"\n} else {\n  console.log(result.reason); // one of ParseFromHeaderFailureReason\n}\n```\n\n### Signature\n\n```typescript\nfunction parseFromHeader(\n  header: string | null | undefined,\n): ParseFromHeaderResult;\n```\n\n### Result shape\n\n```typescript\ntype ParseFromHeaderResult =\n  | { ok: true; value: ValidatedAddress }\n  | { ok: false; reason: ParseFromHeaderFailureReason };\n\ninterface ValidatedAddress {\n  address: string; // lowercased local-part and domain\n}\n```\n\n### Rejection reasons\n\n`parseFromHeader` never falls back to a \"best guess.\" Any of the following inputs return `{ ok: false, reason }` instead of a partially-parsed address:\n\n| `reason` | Trigger |\n|---|---|\n| `empty` | `header` is `null`, `undefined`, or whitespace-only after trimming |\n| `too_long` | Header exceeds 998 UTF-8 bytes (the RFC 5322 §2.1.1 line limit, measured in bytes so multi-byte SMTPUTF8/RFC 6531 characters can't bypass the cap) |\n| `multiple_addresses` | Header contains more than one address (RFC 5322 permits multi-address `From`, but it's rare and ambiguous as an identity) |\n| `group_syntax` | Header uses group syntax, e.g. `Friends: a@b.com, c@d.com;` |\n| `invalid_address` | The single address fails validator's `isEmail` check under the SDK's chosen options, or the parse produced no usable entry |\n\nThe `isEmail` check (via `validator/lib/isEmail`) enforces per-part length limits (64-octet local-part, 255-octet domain), dot-atom rules, hostname-label rules, a required TLD, and other RFC 5321/5322 conformance checks. Its options:\n\n| Option | Value | Effect |\n|---|---|---|\n| `allow_ip_domain` | `true` | Accepts address-literals like `user@[192.168.1.1]` |\n| `require_tld` | `true` | Rejects `user@localhost` |\n| `allow_display_name` | `false` | Only the bare addr-spec is checked (the display name was already stripped by the header parser) |\n| `allow_utf8_local_part` | `true` | Accepts SMTPUTF8 / EAI local-parts |\n\n### Normalization\n\nOn success, `value.address` is lowercased in full, both the local-part and the domain. RFC 5321 §2.4 technically permits case-sensitive local-parts, but every consumer mailbox treats them as case-insensitive in practice; a case-sensitive grant key would otherwise split `Bob@x.com` from `bob@x.com` into separate rows and defeat a primary-key lookup.\n\nNo display name is returned. Deliberately: an input like `Name <user@x.com> <attacker@y.com>` parses as one entry whose `name` field can silently absorb the second address, so surfacing that as a \"parsed name\" here would invite misuse. Call `parseFromHeaderLoose` alongside if you also need a name for display.\n\n## parseFromHeaderLoose\n\nLenient parser for display-only call sites: inbox card \"from\" fields, log lines, debugging output.\n\n```typescript\nimport { parseFromHeaderLoose } from \"@primitivedotdev/sdk/parser\";\n\nconst parsed = parseFromHeaderLoose('\"Alice\" <alice@example.com>');\n// { address: \"alice@example.com\", name: \"Alice\" }\n```\n\nGiven a multi-address header, it returns the first address that passes validation rather than rejecting the header.\n```\n\n### Signature\n\n```typescript\nfunction parseFromHeaderLoose(\n  header: string | null | undefined,\n): ParsedAddress | null;\n```\n\n### Result shape\n\n```typescript\ninterface ParsedAddress {\n  address: string; // lowercased\n  name: string | null;\n}\n```\n\nReturns `null` when the header is `null`/`undefined`, empty after trimming, exceeds the 998-byte limit, or contains no address that passes the same `isEmail` check used by `parseFromHeader`.\n\n### Behavior differences from parseFromHeader\n\n| Case | `parseFromHeader` | `parseFromHeaderLoose` |\n|---|---|---|\n| Multiple addresses | Rejects (`multiple_addresses`) | Returns the first parseable address |\n| Group syntax | Rejects (`group_syntax`) | Flattens into member addresses and returns the first parseable one |\n| No valid address | Returns a typed `reason` | Returns `null` |\n| Display name | Never returned | Returned when present, otherwise `null` |\n\n<Warning>\n\nNames returned by `parseFromHeaderLoose` can include addressparser's recovery output, trailing tokens or garbage preceding the address. Treat `name` as opaque text for display; sanitize before re-emitting it (e.g. into HTML or a re-sent email).\n\n</Warning>\n\n## Choosing between them\n\n- **Authorization, allowlisting, or any trust decision**: use `parseFromHeader` and branch on `result.ok` / `result.reason`.\n- **Showing a sender's name in a UI or log**: use `parseFromHeaderLoose` and treat `name` as untrusted display text.\n\nBoth parsers are pure functions with no network or I/O dependency; they operate only on the header string you pass in. For deciding whether an inbound email's sender domain can be trusted (not just whether the header parses), see [Verifying Inbound Email Authenticity](node-sdk-email-authenticity).\n\n## Next steps\n\n<CardGroup cols={2}>\n\n<Card title=\"Verifying Inbound Email Authenticity\" href=\"node-sdk-email-authenticity\">\n\nUse validateEmailAuth and isTrustedSender to anchor authorization decisions to SPF/DKIM/DMARC results and an expected sending domain.\n\n</Card>\n\n<Card title=\"Parsing Raw Email (.eml)\" href=\"node-sdk-parsing-email\">\n\nParse raw MIME bytes into structured bodies, headers, and attachments, and extract addresses safely from a full message.\n\n</Card>\n\n</CardGroup>","canonical_base_url":"https://test.abhinandan.one","seo_indexing_enabled":true,"last_modified":"2026-08-21T18:22:43.359885+00:00","video_url":null,"voiceover_url":null,"tools_used":[],"demonstrated_by":[],"steps":[],"related_links":[],"intro":null,"prerequisites":[],"verification":[],"troubleshooting":[],"suggest_edit_url":"https://github.com/abhi-browzer/primitive-sdks/edit/main/sdk-node/src/parser/address-parser.ts","raise_issue_url":"https://github.com/abhi-browzer/primitive-sdks/issues/new?title=Docs+feedback%3A+Raw+MIME+Address+Parsing+%28parser%2Faddress%29&body=Page%3A+https%3A%2F%2Ftest.abhinandan.one%2Fnode-sdk-address-parsing","page_feedback_enabled":true,"verified_ref":null,"verified_at":"2026-08-11T18:38:45.205849+00:00"}}