BIMI

Brand Indicators for Message Identification — RFC 9091. BIMI records publish a sender's brand-logo URL in DNS so receiving MTAs can render it next to the message in supported clients (Gmail, Yahoo, Apple Mail). The TXT record format is:

default._bimi. IN TXT "v=BIMI1; l=https://...; a=https://..."

BIMI is layered on a passing DMARC posture (the receiver requires DMARC at quarantine or reject). No-op for senders without DMARC enforcement.

Surface:

b.mail.bimi.recordShape({ logoUrl, vmcUrl?, selector? }) -> string b.mail.bimi.fetchPolicy(domain, opts?) -> record | null b.mail.bimi.parseRecord(text) -> record | null b.mail.bimi.fetchAndVerifyMark({ domain, vmcUrl, ... }) -> verified mark b.mail.bimi.validateTinyPsSvg(svgBytes) -> { ok, violations }

fetchAndVerifyMark fetches a VMC / CMC over HTTPS via b.httpClient, parses it as X.509, validates the chain against the BIMI Group trust anchors (vendored at lib/vendor/bimi-trust-anchors.pem, operator-overridable via trustAnchorsPem), confirms the cert's subjectAltName URI matches the BIMI domain, and confirms the cert carries the BIMI mark-verification policy OID (1.3.6.1.5.5.7.3.31). The verified mark is returned as { svg, evidenceDocument } — svg pulled from the RFC 3709 logotype extension when present, evidenceDocument echoed from the operator-supplied opts.evidenceDocument.

validateTinyPsSvg enforces the AuthIndicators-WG Tiny PS subset: single root , version="1.2", baseProfile="tiny-ps", viewBox present, no script / style / foreignObject / animate / filter / image, no external href / xlink:href references (only #fragment permitted), bounded byte size (32 KiB cap).

b.mail.bimi.recordShape(opts) #

stable0.7.0
{
  {
    logoUrl:   string,    // required - https:// URL to Tiny-PS SVG
    vmcUrl:    string?,   // optional - https:// URL to VMC / CMC PEM
    selector:  string?,   // unused at record-shape time; reserved
                          //   for future per-selector behavior
  }
}

Builds the canonical RFC 9091 BIMI TXT-record string from a logo URL and optional VMC URL. Throws on missing or non-https URLs and on control / record-separator characters in the URLs. Operators publish the returned string at default._bimi. (or the selector subdomain if they're using non-default selectors).

var rec = b.mail.bimi.recordShape({
  logoUrl: "https://example.com/bimi/logo.svg",
  vmcUrl:  "https://example.com/bimi/cert.pem",
});
// -> "v=BIMI1; l=https://example.com/bimi/logo.svg; a=https://example.com/bimi/cert.pem"

b.mail.bimi.parseRecord(text) #

stable0.7.0

Parses a BIMI TXT record into { v, l, a }. Returns null when the text is not a v=BIMI1 record, the l= URL is missing, or the total bytes exceed the 2 KiB sanity cap. Use this when the operator already has the TXT bytes in hand (e.g. an inbound auth-results pipeline carrying the resolved record).

var rv = b.mail.bimi.parseRecord("v=BIMI1; l=https://example.com/logo.svg");
// -> { v: "BIMI1", l: "https://example.com/logo.svg", a: null }

b.mail.bimi.fetchPolicy(domain, opts?) #

stable0.7.0
{
  {
    selector:  string?,                       // default "default"
    dnsLookup: async (qname, type) => rows?,  // operator-supplied resolver
                                              //   (DoH / cache / fixture);
                                              //   default: node:dns.resolveTxt
  }
}

Resolves default._bimi. (or ._bimi. if opts.selector is set) and returns the parsed { v, l, a }. Returns null when no TXT record exists or no record on the resolved name parses as v=BIMI1. Operators feed the returned l= / a= URLs into fetchAndVerifyMark to retrieve the verified mark.

var pol = await b.mail.bimi.fetchPolicy("example.com");
if (pol && pol.a) {
  var verified = await b.mail.bimi.fetchAndVerifyMark({
    domain:  "example.com",
    vmcUrl:  pol.a,
  });
}

b.mail.bimi.validateTinyPsSvg(svgBytes) #

stable0.8.53
{
  svgBytes: Buffer | string
}

Validates a brand-mark SVG against the AuthIndicators-WG Tiny PS profile (RFC 9091 5). Tiny-PS is a strict subset of SVG 1.2: single root with version="1.2" and baseProfile="tiny-ps", viewBox required, byte size up to 32 KiB, no scripts / styles / foreign content / animation / filters / external image refs, no external references in href / xlink:href attributes (only #fragment permitted), no / / processing instructions other than the XML prolog. Returns { ok, violations } where each violation is { code, message }. Throws MailBimiError (bimi/svg-too-large) when the input exceeds the byte cap; throws (bimi/svg-tiny-ps-violation with parse-failed) on tokenizer failure.

var rv = b.mail.bimi.validateTinyPsSvg('');
// -> { ok: true, violations: [] }

b.mail.bimi.fetchAndVerifyMark(opts) #

stable0.8.53
{
  {
    domain:            string,       // required - BIMI domain to assert
                                     //   matches subjectAltName URI
    vmcUrl:            string?,      // VMC PEM URL (https://); operator
                                     //   passes one of vmcUrl / cmcUrl
    cmcUrl:            string?,      // CMC PEM URL (https://); same
    trustAnchorsPem:   string?,      // operator-supplied PEM bundle;
                                     //   defaults to the vendored
                                     //   bimi-trust-anchors.pem
    timeoutMs:         number?,      // default 15s
    maxResponseBytes:  number?,      // default 256 KiB
    audit:             { safeEmit }, // operator-supplied audit dispatcher
    httpClient:        object?,      // default b.httpClient - test-only
                                     //   override for unit tests that
                                     //   want to stub the network call
    evidenceDocument:  string?,      // operator-supplied trademark
                                     //   evidence URL; surfaced on
                                     //   the result for audit logging
  }
}

Fetches a VMC / CMC PEM from opts.vmcUrl (or opts.cmcUrl) over HTTPS, parses it as X.509, validates the chain against the BIMI Group trust anchors (vendored at lib/vendor/bimi-trust-anchors.pem, operator-overridable via trustAnchorsPem), confirms the cert's subjectAltName URI matches the BIMI domain, and confirms the cert carries the BIMI mark-verification ExtendedKeyUsage OID (1.3.6.1.5.5.7.3.31). Returns { ok, mark, certificate, vmcType } where vmcType is "vmc" or "cmc" derived from the cert's policyOIDs, and mark carries the SVG bytes when the cert's RFC 3709 logotype extension is present (or null when not). Throws MailBimiError with one of the documented codes on any failure.

var rv = await b.mail.bimi.fetchAndVerifyMark({
  domain:           "example.com",
  vmcUrl:           "https://example.com/bimi/cert.pem",
  trustAnchorsPem:  "-----BEGIN CERTIFICATE-----\n...",
});
// -> { ok, mark: { svg, evidenceDocument }, certificate, vmcType: "vmc" }

Last updated 2026-08-08T16:39:49.652Z by seeder.