Outbound delivery
Turnkey outbound SMTP composer. Wraps the discovery chain (MX-lookup → MTA-STS-fetch + MX-allowlist match → DANE TLSA query → REQUIRETLS handshake hint) around the existing per-host b.mail.smtpTransport wire-layer, plus deferred-retry scheduling for transient failures and RFC 3464 DSN generation for permanent ones.
Operators no longer have to glue these pieces by hand:
var deliver = b.mail.send.deliver.create({ hostname: "mta1.example.com", policy: { mtaSts: "enforce", dane: "opportunistic" }, dsn: { from: "mailer-daemon@example.com", onPermanentFailure: function (env, hist) { ... } }, resolver: b.network.dns.resolver.create({ ... }), });
var result = await deliver({ from: "ops@example.com", to: ["alice@recipient.com", "bob@other.com"], rfc822: messageBuffer, requireTls: true, }); // → { delivered: [{ recipient, mxHost, tlsProtocol, ... }], // deferred: [{ recipient, reason, retryAfterMs }], // failed: [{ recipient, reason, dsnSent }] }
Composes: - b.network.smtp.policy.mtaSts.fetch + .matchMx → RFC 8461 enforcement - b.network.smtp.policy.dane.tlsa → RFC 7672 TLSA query - b.network.dns.resolver (operator-supplied) → caching + DoH posture - b.mail.smtpTransport → SMTP wire layer - b.mail.requireTls → RFC 8689 REQUIRETLS - b.mailBounce-style RFC 3464 DSN generation → permanent-failure report-mail - b.audit → mail.send.deliver.* events - b.safeAsync.repeating + operator's queue → retry scheduling (deferred deliveries re-enter via the retry.scheduleRetry callback)
The deferred-retry surface is operator-side: this primitive classifies a recipient's outcome as "deferred" and emits a retryAfterMs budget; the operator's queue / scheduler re-invokes deliver for the deferred recipient after that elapses. The primitive does NOT own a background scheduler — that ownership lives with the operator's job-runner so a single deferred-delivery tick can't pin a long-lived process.
b.mail.send.deliver.create(opts) #
{
hostname: string, // required — local hostname for HELO/EHLO + DSN Reporting-MTA
port: number, // default 25 (IANA SMTP, RFC 5321) — set 587 (RFC 6409 submission) or 465 (RFC 8314 implicit-TLS) for a smarthost relay
resolver: object | null, // optional — b.network.dns.resolver handle; falls back to node:dns when omitted
policy: {
mtaSts: "enforce" | "testing" | "off", // default "enforce" — RFC 8461 posture
dane: "opportunistic" | "enforce" | "off", // default "opportunistic" — RFC 7672
},
retry: {
maxAttempts: number, // default 5
backoffMs: Array, // default [1m, 5m, 15m, 1h, 4h]
},
dsn: {
from: string, // required when dsn.onPermanentFailure is set
onPermanentFailure: function (envelope, result, dsnMessage) → Promise,
},
timeouts: {
mxLookupMs: number, // default 10s
perHostMs: number, // default 60s
},
audit: boolean, // default true
}
Build a turnkey delivery handle. Returns a deliver(envelope) function that takes a single multi-recipient envelope, resolves MX records per recipient domain, applies the operator's configured MTA-STS / DANE policy, attempts delivery via b.mail.smtpTransport, and returns a per-recipient outcome split into delivered / deferred / failed arrays.
Deferred recipients carry retryAfterMs budgets the operator's queue / scheduler honors by re-invoking deliver for that subset after the budget elapses. The primitive does not own a background scheduler — operator job-runner owns the retry lifecycle.
Failed recipients trigger DSN composition: a RFC 3464 multipart/ report message is built per failed recipient and handed to the operator-supplied dsn.onPermanentFailure(envelope, recipientResult, dsnMessage) callback. The callback is responsible for delivering the DSN itself (typically by re-entering the same deliver handle with the original sender as recipient — but operators who want a separate transport for DSNs wire that here).
var deliver = b.mail.send.deliver.create({
hostname: "mta1.example.com",
policy: { mtaSts: "enforce", dane: "opportunistic" },
dsn: { from: "mailer-daemon@example.com",
onPermanentFailure: function (env, res, dsn) {
return deliver({ from: env.from, to: [env.from], rfc822: Buffer.from(dsn) });
} },
});
var result = await deliver({
from: "ops@example.com",
to: ["alice@recipient.com"],
rfc822: messageBuffer,
});
typeof result.delivered; // → "object" (array)
typeof result.deferred; // → "object" (array)
typeof result.failed; // → "object" (array)
Last updated 2026-08-08T16:39:49.652Z by seeder.