@softure-ai/mailing 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +108 -25
  3. package/dist/cli/run.d.ts +3 -1
  4. package/dist/cli/run.d.ts.map +1 -1
  5. package/dist/cli/run.js +141 -25
  6. package/dist/cli/run.js.map +1 -1
  7. package/dist/contract.d.ts +48 -8
  8. package/dist/contract.d.ts.map +1 -1
  9. package/dist/contract.js +2 -0
  10. package/dist/contract.js.map +1 -1
  11. package/dist/index.d.ts +12 -3
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +3 -3
  14. package/dist/index.js.map +1 -1
  15. package/dist/messages/en.d.ts +2 -0
  16. package/dist/messages/en.d.ts.map +1 -1
  17. package/dist/messages/en.js +2 -0
  18. package/dist/messages/en.js.map +1 -1
  19. package/dist/messages/index.d.ts +4 -0
  20. package/dist/messages/index.d.ts.map +1 -1
  21. package/dist/messages/pl.d.ts.map +1 -1
  22. package/dist/messages/pl.js +2 -0
  23. package/dist/messages/pl.js.map +1 -1
  24. package/dist/next/actions.d.ts.map +1 -1
  25. package/dist/next/actions.js +6 -6
  26. package/dist/next/actions.js.map +1 -1
  27. package/dist/next/pages.d.ts.map +1 -1
  28. package/dist/next/pages.js +8 -6
  29. package/dist/next/pages.js.map +1 -1
  30. package/dist/next/route.d.ts +2 -1
  31. package/dist/next/route.d.ts.map +1 -1
  32. package/dist/next/route.js +6 -4
  33. package/dist/next/route.js.map +1 -1
  34. package/dist/options.d.ts +15 -1
  35. package/dist/options.d.ts.map +1 -1
  36. package/dist/options.js +32 -1
  37. package/dist/options.js.map +1 -1
  38. package/dist/providers/resend.d.ts.map +1 -1
  39. package/dist/providers/resend.js +12 -6
  40. package/dist/providers/resend.js.map +1 -1
  41. package/dist/schema.d.ts +17 -0
  42. package/dist/schema.d.ts.map +1 -1
  43. package/dist/schema.js +2 -0
  44. package/dist/schema.js.map +1 -1
  45. package/dist/server/campaigns.d.ts +30 -4
  46. package/dist/server/campaigns.d.ts.map +1 -1
  47. package/dist/server/campaigns.js +67 -12
  48. package/dist/server/campaigns.js.map +1 -1
  49. package/dist/server/deliveries.d.ts +30 -2
  50. package/dist/server/deliveries.d.ts.map +1 -1
  51. package/dist/server/deliveries.js +58 -23
  52. package/dist/server/deliveries.js.map +1 -1
  53. package/dist/server/dns.d.ts +48 -1
  54. package/dist/server/dns.d.ts.map +1 -1
  55. package/dist/server/dns.js +124 -15
  56. package/dist/server/dns.js.map +1 -1
  57. package/dist/server/index.d.ts +4 -4
  58. package/dist/server/index.d.ts.map +1 -1
  59. package/dist/server/index.js +3 -3
  60. package/dist/server/index.js.map +1 -1
  61. package/dist/server/send-mail.d.ts +3 -1
  62. package/dist/server/send-mail.d.ts.map +1 -1
  63. package/dist/server/send-mail.js +18 -6
  64. package/dist/server/send-mail.js.map +1 -1
  65. package/dist/server/suppressions.d.ts +8 -6
  66. package/dist/server/suppressions.d.ts.map +1 -1
  67. package/dist/server/suppressions.js +23 -7
  68. package/dist/server/suppressions.js.map +1 -1
  69. package/dist/server/unsubscribe-link.d.ts +23 -0
  70. package/dist/server/unsubscribe-link.d.ts.map +1 -1
  71. package/dist/server/unsubscribe-link.js +30 -1
  72. package/dist/server/unsubscribe-link.js.map +1 -1
  73. package/migrations/0003_add_delivery_provider_status.sql +13 -0
  74. package/module.json +1 -1
  75. package/package.json +1 -1
  76. package/src/cli/run.ts +164 -29
  77. package/src/contract.ts +49 -6
  78. package/src/index.ts +8 -3
  79. package/src/messages/en.ts +2 -0
  80. package/src/messages/pl.ts +2 -0
  81. package/src/next/actions.ts +5 -6
  82. package/src/next/pages.tsx +10 -7
  83. package/src/next/route.ts +6 -4
  84. package/src/options.ts +36 -2
  85. package/src/providers/resend.ts +11 -7
  86. package/src/schema.ts +2 -0
  87. package/src/server/campaigns.ts +95 -17
  88. package/src/server/deliveries.ts +89 -29
  89. package/src/server/dns.ts +174 -16
  90. package/src/server/index.ts +17 -0
  91. package/src/server/send-mail.ts +30 -6
  92. package/src/server/suppressions.ts +23 -8
  93. package/src/server/unsubscribe-link.ts +41 -1
@@ -1 +1 @@
1
- {"version":3,"file":"deliveries.js","sourceRoot":"","sources":["../../src/server/deliveries.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deliveries.js","sourceRoot":"","sources":["../../src/server/deliveries.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  export type DnsCheckStatus = "pass" | "warn" | "fail";
2
- export type DnsFinding = "found" | "missing" | "multiple" | "permissive" | "revoked" | "monitor-only" | "inherited" | "lookup-failed";
2
+ export type DnsFinding = "found" | "missing" | "multiple" | "permissive" | "revoked" | "monitor-only" | "inherited" | "weak" | "null-mx" | "unexpected-target" | "lookup-failed";
3
3
  export interface DnsCheck {
4
4
  readonly status: DnsCheckStatus;
5
5
  readonly finding: DnsFinding;
@@ -13,8 +13,37 @@ export interface SenderDnsReport {
13
13
  readonly spf: DnsCheck;
14
14
  readonly dkim: DnsCheck;
15
15
  readonly dmarc: DnsCheck;
16
+ /** The reply-to domain's MX, when `replyTo` was given. */
17
+ readonly replyTo: DnsCheck | null;
18
+ /** One check per `returnPath` host, in the order given. */
19
+ readonly returnPath: readonly DnsCheck[];
16
20
  }
17
21
  export type ResolveTxt = (hostname: string) => Promise<string[][]>;
22
+ export interface MxRecord {
23
+ readonly exchange: string;
24
+ readonly priority: number;
25
+ }
26
+ export type ResolveMx = (hostname: string) => Promise<MxRecord[]>;
27
+ export type ResolveCname = (hostname: string) => Promise<string[]>;
28
+ export type DmarcPolicy = "quarantine" | "reject";
29
+ export type DmarcAlignment = "r" | "s";
30
+ /** The least a DMARC record must carry; a weaker one fails as `weak`. Absent tags count as their defaults. */
31
+ export interface DmarcExpectation {
32
+ /** The policy for the checked domain: `p`, or `sp ?? p` of a parent's record. Also requires `pct` 100. */
33
+ readonly policy?: DmarcPolicy;
34
+ /** The policy for subdomains: `sp ?? p`. */
35
+ readonly subdomainPolicy?: DmarcPolicy;
36
+ /** `adkim`; absent means relaxed (`r`). */
37
+ readonly adkim?: DmarcAlignment;
38
+ /** `aspf`; absent means relaxed (`r`). */
39
+ readonly aspf?: DmarcAlignment;
40
+ }
41
+ /** A host the provider uses for MAIL FROM or bounces. */
42
+ export interface ReturnPathHost {
43
+ readonly host: string;
44
+ /** When set, a CNAME must point at this domain or under it (`rmta.net` accepts `send.forge.rmta.net`). */
45
+ readonly targetDomain?: string;
46
+ }
18
47
  export interface CheckSenderDnsOptions {
19
48
  /** DKIM selectors to look up under `_domainkey`. Default `["resend"]`, the Resend selector. */
20
49
  readonly dkimSelectors?: readonly string[];
@@ -23,9 +52,27 @@ export interface CheckSenderDnsOptions {
23
52
  * return path); DMARC accepts that in relaxed alignment.
24
53
  */
25
54
  readonly spfHosts?: readonly string[];
55
+ /** Turns a DMARC record weaker than this into a `fail` (e.g. `{ policy: "reject", adkim: "s", aspf: "s" }`). */
56
+ readonly expectDmarc?: DmarcExpectation;
57
+ /**
58
+ * Where replies go (an address, `Name <address>` or a domain): its domain must have MX records and at most one
59
+ * SPF record, or replies bounce while the sender checks pass.
60
+ */
61
+ readonly replyTo?: string;
62
+ /** Hosts that must resolve as a CNAME or with MX records; `resendReturnPath(domain)` gives Resend's. */
63
+ readonly returnPath?: readonly ReturnPathHost[];
26
64
  readonly resolveTxt?: ResolveTxt;
65
+ readonly resolveMx?: ResolveMx;
66
+ readonly resolveCname?: ResolveCname;
27
67
  }
28
68
  export declare const DEFAULT_DKIM_SELECTORS: readonly string[];
69
+ /** Domain of the CNAME targets Resend publishes for its return-path hosts. */
70
+ export declare const RESEND_RETURN_PATH_DOMAIN = "rmta.net";
71
+ /**
72
+ * Resend's return-path hosts: `send.<domain>` (MAIL FROM) and `rsend.<domain>`, CNAMEs to `*.rmta.net`. Domains
73
+ * set up before Resend published `rsend` have MX records on `send` and no `rsend`: check `send` alone there.
74
+ */
75
+ export declare function resendReturnPath(domain: string): ReturnPathHost[];
29
76
  /** Reads the SPF, DKIM and DMARC records of `domain`. Never throws: a failed lookup is a finding. */
30
77
  export declare function checkSenderDns(domain: string, options?: CheckSenderDnsOptions): Promise<SenderDnsReport>;
31
78
  /** The domain part of a sender (`Plan <hello@mail.example.com>` gives `mail.example.com`). */
@@ -1 +1 @@
1
- {"version":3,"file":"dns.d.ts","sourceRoot":"","sources":["../../src/server/dns.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEtD,MAAM,MAAM,UAAU,GAClB,OAAO,GACP,SAAS,GACT,UAAU,GACV,YAAY,GACZ,SAAS,GACT,cAAc,GACd,WAAW,GACX,eAAe,CAAC;AAEpB,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;CAC1B;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAEnE,MAAM,WAAW,qBAAqB;IACpC,+FAA+F;IAC/F,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;CAClC;AAED,eAAO,MAAM,sBAAsB,EAAE,SAAS,MAAM,EAAe,CAAC;AAEpE,qGAAqG;AACrG,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,eAAe,CAAC,CAUlH;AAED,8FAA8F;AAC9F,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOpD"}
1
+ {"version":3,"file":"dns.d.ts","sourceRoot":"","sources":["../../src/server/dns.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,38 @@
1
1
  // The sender domain's DNS, as receivers check it: SPF (RFC 7208), DKIM (RFC 6376) and DMARC
2
- // (RFC 7489). Without all three, list mail lands in spam or is refused outright. The check only
3
- // reads public TXT records; it cannot see whether the provider signs with the published key.
4
- import { resolveTxt as resolveTxtRecords } from "node:dns/promises";
2
+ // (RFC 7489). Without all three, list mail lands in spam or is refused outright. On request it also
3
+ // holds DMARC to a required minimum, checks that the reply-to domain accepts mail (MX) and that the
4
+ // provider's return-path hosts resolve. The check only reads public records; it cannot see whether
5
+ // the provider signs with the published key.
6
+ import { resolveCname as resolveCnameRecords, resolveMx as resolveMxRecords, resolveTxt as resolveTxtRecords } from "node:dns/promises";
5
7
  export const DEFAULT_DKIM_SELECTORS = ["resend"];
8
+ /** Domain of the CNAME targets Resend publishes for its return-path hosts. */
9
+ export const RESEND_RETURN_PATH_DOMAIN = "rmta.net";
10
+ /**
11
+ * Resend's return-path hosts: `send.<domain>` (MAIL FROM) and `rsend.<domain>`, CNAMEs to `*.rmta.net`. Domains
12
+ * set up before Resend published `rsend` have MX records on `send` and no `rsend`: check `send` alone there.
13
+ */
14
+ export function resendReturnPath(domain) {
15
+ const name = normalizeHost(domain);
16
+ return [
17
+ { host: `send.${name}`, targetDomain: RESEND_RETURN_PATH_DOMAIN },
18
+ { host: `rsend.${name}`, targetDomain: RESEND_RETURN_PATH_DOMAIN },
19
+ ];
20
+ }
6
21
  /** Reads the SPF, DKIM and DMARC records of `domain`. Never throws: a failed lookup is a finding. */
7
22
  export async function checkSenderDns(domain, options = {}) {
8
- const name = domain.trim().toLowerCase().replace(/\.$/, "");
23
+ const name = normalizeHost(domain);
9
24
  const resolveTxt = options.resolveTxt ?? resolveTxtRecords;
10
25
  const lookup = (host) => lookupTxt(resolveTxt, host);
11
- const [spf, dkim, dmarc] = await Promise.all([
26
+ const lookupMx = (host) => lookupRecords(options.resolveMx ?? resolveMxRecords, host);
27
+ const lookupCname = (host) => lookupRecords(options.resolveCname ?? resolveCnameRecords, host);
28
+ const [spf, dkim, dmarc, replyTo, returnPath] = await Promise.all([
12
29
  checkSpf(lookup, options.spfHosts ?? [name]),
13
30
  checkDkim(lookup, (options.dkimSelectors ?? DEFAULT_DKIM_SELECTORS).map((selector) => `${selector}._domainkey.${name}`)),
14
- checkDmarc(lookup, name),
31
+ checkDmarc(lookup, name, options.expectDmarc),
32
+ options.replyTo === undefined ? null : checkReplyPath(lookup, lookupMx, normalizeHost(getSenderDomain(options.replyTo))),
33
+ Promise.all((options.returnPath ?? []).map((path) => checkReturnPath(lookupCname, lookupMx, path))),
15
34
  ]);
16
- return { domain: name, spf, dkim, dmarc };
35
+ return { domain: name, spf, dkim, dmarc, replyTo, returnPath };
17
36
  }
18
37
  /** The domain part of a sender (`Plan <hello@mail.example.com>` gives `mail.example.com`). */
19
38
  export function getSenderDomain(from) {
@@ -24,11 +43,13 @@ export function getSenderDomain(from) {
24
43
  const address = open !== -1 && close > open ? from.slice(open + 1, close) : from;
25
44
  return address.slice(address.lastIndexOf("@") + 1).trim().toLowerCase();
26
45
  }
46
+ function normalizeHost(host) {
47
+ return host.trim().toLowerCase().replace(/\.$/, "");
48
+ }
27
49
  const NO_RECORD_CODES = new Set(["ENOTFOUND", "ENODATA", "NXDOMAIN"]);
28
- async function lookupTxt(resolveTxt, host) {
50
+ async function lookupRecords(resolve, host) {
29
51
  try {
30
- // A TXT record may arrive in 255-byte chunks; they form one string.
31
- const records = (await resolveTxt(host)).map((chunks) => chunks.join(""));
52
+ const records = await resolve(host);
32
53
  return records.length === 0 ? { kind: "none" } : { kind: "records", records };
33
54
  }
34
55
  catch (error) {
@@ -36,6 +57,13 @@ async function lookupTxt(resolveTxt, host) {
36
57
  return typeof code === "string" && NO_RECORD_CODES.has(code) ? { kind: "none" } : { kind: "error" };
37
58
  }
38
59
  }
60
+ async function lookupTxt(resolveTxt, host) {
61
+ // A TXT record may arrive in 255-byte chunks; they form one string.
62
+ return lookupRecords(async (name) => (await resolveTxt(name)).map((chunks) => chunks.join("")), host);
63
+ }
64
+ function isSpfRecord(record) {
65
+ return /^v=spf1(\s|$)/i.test(record.trim());
66
+ }
39
67
  function startsWithTag(record, tag) {
40
68
  return record.trim().toLowerCase().startsWith(tag);
41
69
  }
@@ -48,7 +76,7 @@ async function checkSpf(lookup, hosts) {
48
76
  lookupFailed ??= host;
49
77
  continue;
50
78
  }
51
- const records = answer.kind === "records" ? answer.records.filter((record) => /^v=spf1(\s|$)/i.test(record.trim())) : [];
79
+ const records = answer.kind === "records" ? answer.records.filter(isSpfRecord) : [];
52
80
  if (records.length > 1)
53
81
  return { status: "fail", finding: "multiple", host, record: null };
54
82
  const record = records[0];
@@ -83,9 +111,10 @@ async function checkDkim(lookup, hosts) {
83
111
  }
84
112
  /**
85
113
  * `_dmarc.<domain>`, or the nearest parent's record (the organisational domain's policy, with
86
- * `sp=` for subdomains when it is set). `p=none` only reports; it protects nothing.
114
+ * `sp=` for subdomains when it is set). `p=none` only reports; it protects nothing. With an
115
+ * expectation, a record weaker than it fails as `weak`.
87
116
  */
88
- async function checkDmarc(lookup, domain) {
117
+ async function checkDmarc(lookup, domain, expected) {
89
118
  const labels = domain.split(".");
90
119
  const first = `_dmarc.${domain}`;
91
120
  for (let index = 0; index <= labels.length - 2; index += 1) {
@@ -102,12 +131,92 @@ async function checkDmarc(lookup, domain) {
102
131
  if (record === undefined)
103
132
  continue;
104
133
  const inherited = host !== first;
105
- const tag = (name) => new RegExp(`(?:^|;)\\s*${name}=([^;]*)`, "i").exec(record)?.[1]?.trim().toLowerCase();
106
- const policy = (inherited ? (tag("sp") ?? tag("p")) : tag("p")) ?? "none";
134
+ const tags = readDmarcTags(record);
135
+ const policy = (inherited ? (tags.get("sp") ?? tags.get("p")) : tags.get("p")) ?? "none";
136
+ if (expected !== undefined && !meetsDmarcExpectation(tags, policy, expected))
137
+ return { status: "fail", finding: "weak", host, record };
107
138
  if (policy === "none")
108
139
  return { status: "warn", finding: "monitor-only", host, record };
109
140
  return inherited ? { status: "pass", finding: "inherited", host, record } : { status: "pass", finding: "found", host, record };
110
141
  }
111
142
  return { status: "fail", finding: "missing", host: first, record: null };
112
143
  }
144
+ /** `tag=value` pairs of a DMARC record, names and values lower-cased; the first occurrence wins. */
145
+ function readDmarcTags(record) {
146
+ const tags = new Map();
147
+ for (const part of record.split(";")) {
148
+ const separator = part.indexOf("=");
149
+ if (separator === -1)
150
+ continue;
151
+ const name = part.slice(0, separator).trim().toLowerCase();
152
+ if (!tags.has(name))
153
+ tags.set(name, part.slice(separator + 1).trim().toLowerCase());
154
+ }
155
+ return tags;
156
+ }
157
+ const POLICY_RANK = { none: 0, quarantine: 1, reject: 2 };
158
+ /** An unknown policy value counts as `none`, as receivers treat an invalid `p=`. */
159
+ function rankPolicy(policy) {
160
+ return (policy === undefined ? undefined : POLICY_RANK[policy]) ?? 0;
161
+ }
162
+ function meetsAlignment(actual, expected) {
163
+ return expected !== "s" || actual === "s";
164
+ }
165
+ function meetsDmarcExpectation(tags, policy, expected) {
166
+ if (expected.policy !== undefined) {
167
+ if (rankPolicy(policy) < rankPolicy(expected.policy))
168
+ return false;
169
+ const percent = tags.get("pct");
170
+ if (percent !== undefined && Number(percent) !== 100)
171
+ return false;
172
+ }
173
+ if (expected.subdomainPolicy !== undefined && rankPolicy(tags.get("sp") ?? tags.get("p")) < rankPolicy(expected.subdomainPolicy))
174
+ return false;
175
+ return meetsAlignment(tags.get("adkim"), expected.adkim) && meetsAlignment(tags.get("aspf"), expected.aspf);
176
+ }
177
+ function formatMx(records) {
178
+ return [...records]
179
+ .sort((left, right) => left.priority - right.priority)
180
+ .map((record) => `${String(record.priority)} ${normalizeHost(record.exchange) || "."}`)
181
+ .join(", ");
182
+ }
183
+ /** A null MX (RFC 7505: one record, exchange `.`) says the domain accepts no mail. Node reports it as `""`. */
184
+ function isNullMx(records) {
185
+ return records.length === 1 && normalizeHost(records[0]?.exchange ?? "") === "";
186
+ }
187
+ /** The reply-to domain must accept mail (MX, not a null MX) and publish at most one SPF record. */
188
+ async function checkReplyPath(lookup, lookupMx, host) {
189
+ const mx = await lookupMx(host);
190
+ if (mx.kind === "error")
191
+ return { status: "fail", finding: "lookup-failed", host, record: null };
192
+ if (mx.kind === "none")
193
+ return { status: "fail", finding: "missing", host, record: null };
194
+ if (isNullMx(mx.records))
195
+ return { status: "fail", finding: "null-mx", host, record: formatMx(mx.records) };
196
+ const txt = await lookup(host);
197
+ if (txt.kind === "error")
198
+ return { status: "fail", finding: "lookup-failed", host, record: null };
199
+ if (txt.kind === "records" && txt.records.filter(isSpfRecord).length > 1)
200
+ return { status: "fail", finding: "multiple", host, record: null };
201
+ return { status: "pass", finding: "found", host, record: formatMx(mx.records) };
202
+ }
203
+ /** A CNAME (to `targetDomain` or under it, when set), else MX records. Strings, not patterns: the domain is input. */
204
+ async function checkReturnPath(lookupCname, lookupMx, path) {
205
+ const host = normalizeHost(path.host);
206
+ const cname = await lookupCname(host);
207
+ if (cname.kind === "error")
208
+ return { status: "fail", finding: "lookup-failed", host, record: null };
209
+ if (cname.kind === "records") {
210
+ const target = normalizeHost(cname.records[0] ?? "");
211
+ const expected = path.targetDomain === undefined ? null : normalizeHost(path.targetDomain);
212
+ const matches = expected === null || target === expected || target.endsWith(`.${expected}`);
213
+ return matches ? { status: "pass", finding: "found", host, record: target } : { status: "fail", finding: "unexpected-target", host, record: target };
214
+ }
215
+ const mx = await lookupMx(host);
216
+ if (mx.kind === "error")
217
+ return { status: "fail", finding: "lookup-failed", host, record: null };
218
+ if (mx.kind === "none" || isNullMx(mx.records))
219
+ return { status: "fail", finding: "missing", host, record: null };
220
+ return { status: "pass", finding: "found", host, record: formatMx(mx.records) };
221
+ }
113
222
  //# sourceMappingURL=dns.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dns.js","sourceRoot":"","sources":["../../src/server/dns.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dns.js","sourceRoot":"","sources":["../../src/server/dns.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,12 @@
1
1
  export { getCampaignProblems, parseCampaignFile, parseRecipientList, type CampaignContent, type CampaignFile, type CampaignFileResult } from "./campaign-file.js";
2
- export { getCampaignContentHash, planCampaign, registerCampaign, sendCampaign, type CampaignErrorCode, type CampaignPlan, type CampaignSummary, type SendCampaignOptions, } from "./campaigns.js";
3
- export { DEFAULT_MAX_ATTEMPTS, DEFAULT_STALE_CLAIM_MS, deliverOnce, type DeliverOptions, type Delivery, type DeliveryContext, type DeliveryOutcome, } from "./deliveries.js";
4
- export { checkSenderDns, DEFAULT_DKIM_SELECTORS, getSenderDomain, type CheckSenderDnsOptions, type DnsCheck, type DnsCheckStatus, type DnsFinding, type ResolveTxt, type SenderDnsReport, } from "./dns.js";
2
+ export { getCampaignContentHash, planCampaign, registerCampaign, sendCampaign, type CampaignErrorCode, type CampaignHalt, type CampaignPlan, type CampaignSummary, type SendCampaignOptions, } from "./campaigns.js";
3
+ export { DEFAULT_MAX_ATTEMPTS, DEFAULT_STALE_CLAIM_MS, DEFAULT_UNCERTAIN_CLAIM_MS, deliverOnce, type DeliverOptions, type Delivery, type DeliveryContext, type DeliveryOutcome, type HaltingErrorCode, } from "./deliveries.js";
4
+ export { checkSenderDns, DEFAULT_DKIM_SELECTORS, getSenderDomain, RESEND_RETURN_PATH_DOMAIN, resendReturnPath, type CheckSenderDnsOptions, type DmarcAlignment, type DmarcExpectation, type DmarcPolicy, type DnsCheck, type DnsCheckStatus, type DnsFinding, type MxRecord, type ResolveCname, type ResolveMx, type ResolveTxt, type ReturnPathHost, type SenderDnsReport, } from "./dns.js";
5
5
  export { checkMailingTables } from "./health.js";
6
6
  export { addHtmlFooter, addTextFooter, getListUnsubscribeHeaders, SIGNATURE_SEPARATOR } from "./list-mail.js";
7
7
  export { getMailingModule, getMailingOptions, getMailingRoutes, type MailingRoutes } from "./options.js";
8
8
  export { sendMail, type MailContext } from "./send-mail.js";
9
9
  export { isSuppressed, liftSuppression, suppressRecipient, unsubscribe, type SuppressionContext } from "./suppressions.js";
10
- export { buildUnsubscribeLinks, getRecipientKey, MIN_UNSUBSCRIBE_SECRET_LENGTH, readUnsubscribeSecrets, readUnsubscribeToken, RECIPIENT_PARAM, signRecipientKey, SIGNATURE_PARAM, UNSUBSCRIBE_PREVIOUS_SECRET_ENV, UNSUBSCRIBE_SECRET_ENV, verifyUnsubscribeToken, type Env, type UnsubscribeLinks, type UnsubscribeSecrets, type UnsubscribeToken, } from "./unsubscribe-link.js";
10
+ export { buildUnsubscribeLinks, getRecipientKey, getUnsubscribeLinkParams, MAX_LEGACY_VALUE_LENGTH, readUnsubscribeLink, MIN_UNSUBSCRIBE_SECRET_LENGTH, readUnsubscribeSecrets, readUnsubscribeToken, RECIPIENT_PARAM, signRecipientKey, SIGNATURE_PARAM, UNSUBSCRIBE_PREVIOUS_SECRET_ENV, UNSUBSCRIBE_SECRET_ENV, verifyUnsubscribeToken, type Env, type LinkParams, type UnsubscribeLink, type UnsubscribeLinks, type UnsubscribeSecrets, type UnsubscribeToken, } from "./unsubscribe-link.js";
11
11
  export { validateMail, type MailValidation, type ValidMail } from "./validate-mail.js";
12
12
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAClK,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,eAAe,GACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,eAAe,EACf,KAAK,qBAAqB,EAC1B,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACzG,OAAO,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC3H,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,+BAA+B,EAC/B,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,GAAG,EACR,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAClK,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,WAAW,EACX,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,eAAe,EACf,yBAAyB,EACzB,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AACzG,OAAO,EAAE,QAAQ,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC3H,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,+BAA+B,EAC/B,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,GAAG,EACR,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC"}
@@ -2,13 +2,13 @@
2
2
  // scope; `next/*` imports are not allowed here (ESLint `no-restricted-imports`, NFR-3).
3
3
  export { getCampaignProblems, parseCampaignFile, parseRecipientList } from "./campaign-file.js";
4
4
  export { getCampaignContentHash, planCampaign, registerCampaign, sendCampaign, } from "./campaigns.js";
5
- export { DEFAULT_MAX_ATTEMPTS, DEFAULT_STALE_CLAIM_MS, deliverOnce, } from "./deliveries.js";
6
- export { checkSenderDns, DEFAULT_DKIM_SELECTORS, getSenderDomain, } from "./dns.js";
5
+ export { DEFAULT_MAX_ATTEMPTS, DEFAULT_STALE_CLAIM_MS, DEFAULT_UNCERTAIN_CLAIM_MS, deliverOnce, } from "./deliveries.js";
6
+ export { checkSenderDns, DEFAULT_DKIM_SELECTORS, getSenderDomain, RESEND_RETURN_PATH_DOMAIN, resendReturnPath, } from "./dns.js";
7
7
  export { checkMailingTables } from "./health.js";
8
8
  export { addHtmlFooter, addTextFooter, getListUnsubscribeHeaders, SIGNATURE_SEPARATOR } from "./list-mail.js";
9
9
  export { getMailingModule, getMailingOptions, getMailingRoutes } from "./options.js";
10
10
  export { sendMail } from "./send-mail.js";
11
11
  export { isSuppressed, liftSuppression, suppressRecipient, unsubscribe } from "./suppressions.js";
12
- export { buildUnsubscribeLinks, getRecipientKey, MIN_UNSUBSCRIBE_SECRET_LENGTH, readUnsubscribeSecrets, readUnsubscribeToken, RECIPIENT_PARAM, signRecipientKey, SIGNATURE_PARAM, UNSUBSCRIBE_PREVIOUS_SECRET_ENV, UNSUBSCRIBE_SECRET_ENV, verifyUnsubscribeToken, } from "./unsubscribe-link.js";
12
+ export { buildUnsubscribeLinks, getRecipientKey, getUnsubscribeLinkParams, MAX_LEGACY_VALUE_LENGTH, readUnsubscribeLink, MIN_UNSUBSCRIBE_SECRET_LENGTH, readUnsubscribeSecrets, readUnsubscribeToken, RECIPIENT_PARAM, signRecipientKey, SIGNATURE_PARAM, UNSUBSCRIBE_PREVIOUS_SECRET_ENV, UNSUBSCRIBE_SECRET_ENV, verifyUnsubscribeToken, } from "./unsubscribe-link.js";
13
13
  export { validateMail } from "./validate-mail.js";
14
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,wFAAwF;AACxF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,kBAAkB,EAAoE,MAAM,oBAAoB,CAAC;AAClK,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,YAAY,GAKb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,WAAW,GAKZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,eAAe,GAOhB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAsB,MAAM,cAAc,CAAC;AACzG,OAAO,EAAE,QAAQ,EAAoB,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AAC3H,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,+BAA+B,EAC/B,sBAAsB,EACtB,sBAAsB,GAKvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAuC,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,wFAAwF;AACxF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,kBAAkB,EAAoE,MAAM,oBAAoB,CAAC;AAClK,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,YAAY,GAMb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,WAAW,GAMZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,eAAe,EACf,yBAAyB,EACzB,gBAAgB,GAcjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,yBAAyB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC9G,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAsB,MAAM,cAAc,CAAC;AACzG,OAAO,EAAE,QAAQ,EAAoB,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AAC3H,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,uBAAuB,EACvB,mBAAmB,EACnB,6BAA6B,EAC7B,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,+BAA+B,EAC/B,sBAAsB,EACtB,sBAAsB,GAOvB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAuC,MAAM,oBAAoB,CAAC"}
@@ -12,7 +12,9 @@ export interface MailContext {
12
12
  /**
13
13
  * Sends `mail` and resolves with the provider's message id or a `mailing.*` code:
14
14
  * `invalid_input` (fix the input), `rejected` (do not retry), `unavailable` (retry later with the
15
- * same `idempotencyKey`), `suppressed` (a list mail to someone who unsubscribed; do not retry).
15
+ * same `idempotencyKey`), `suppressed` (a list mail to someone who unsubscribed; do not retry),
16
+ * `provider_refused` / `quota_exceeded` (the account cannot send: stop, fix or wait, then retry). A
17
+ * failure the provider answered with an HTTP status carries it as `httpStatus`.
16
18
  * Throws only when the module is not enabled, or for list mail without `context.db`.
17
19
  */
18
20
  export declare function sendMail(context: MailContext, mail: OutgoingMail, options?: SendMailOptions): Promise<SendMailResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"send-mail.d.ts","sourceRoot":"","sources":["../../src/server/send-mail.ts"],"names":[],"mappings":"AAKA,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAgE,KAAK,YAAY,EAA8C,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAQxM;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC;CACzB;AAID;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2B/H"}
1
+ {"version":3,"file":"send-mail.d.ts","sourceRoot":"","sources":["../../src/server/send-mail.ts"],"names":[],"mappings":"AAKA,OAAO,EAAW,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAIL,KAAK,YAAY,EAIjB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAQxB;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC;CACzB;AAID;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2B/H"}
@@ -4,7 +4,7 @@
4
4
  // envelope or the sender. List mail (any kind but `transactional`) also gets a signed unsubscribe
5
5
  // link in a footer and the RFC 8058 headers, and is refused for a recipient who unsubscribed.
6
6
  import { err, ok } from "@softure-ai/core";
7
- import { TRANSACTIONAL_KIND } from "../contract.js";
7
+ import { TRANSACTIONAL_KIND, } from "../contract.js";
8
8
  import { addHtmlFooter, addTextFooter, getListUnsubscribeHeaders } from "./list-mail.js";
9
9
  import { getMailingModule, getMailingOptions } from "./options.js";
10
10
  import { isSuppressed } from "./suppressions.js";
@@ -13,7 +13,9 @@ import { validateMail } from "./validate-mail.js";
13
13
  /**
14
14
  * Sends `mail` and resolves with the provider's message id or a `mailing.*` code:
15
15
  * `invalid_input` (fix the input), `rejected` (do not retry), `unavailable` (retry later with the
16
- * same `idempotencyKey`), `suppressed` (a list mail to someone who unsubscribed; do not retry).
16
+ * same `idempotencyKey`), `suppressed` (a list mail to someone who unsubscribed; do not retry),
17
+ * `provider_refused` / `quota_exceeded` (the account cannot send: stop, fix or wait, then retry). A
18
+ * failure the provider answered with an HTTP status carries it as `httpStatus`.
17
19
  * Throws only when the module is not enabled, or for list mail without `context.db`.
18
20
  */
19
21
  export async function sendMail(context, mail, options = {}) {
@@ -37,10 +39,16 @@ export async function sendMail(context, mail, options = {}) {
37
39
  if (outcome.status === "sent") {
38
40
  return ok({ id: outcome.id, provider: provider.name });
39
41
  }
40
- const code = `mailing.${outcome.status}`;
42
+ const code = FAILURE_CODES[outcome.status];
41
43
  logFailure(provider, code, { status: outcome.httpStatus });
42
- return err(code);
44
+ return outcome.httpStatus === undefined ? err(code) : { ...err(code), httpStatus: outcome.httpStatus };
43
45
  }
46
+ const FAILURE_CODES = {
47
+ rejected: "mailing.rejected",
48
+ unavailable: "mailing.unavailable",
49
+ refused: "mailing.provider_refused",
50
+ quota_exceeded: "mailing.quota_exceeded",
51
+ };
44
52
  /**
45
53
  * A list mail with its footer and headers, or why it must not go out. Fails closed: without the
46
54
  * secret, or when the suppression list cannot be read, nothing is sent.
@@ -109,11 +117,15 @@ function readOutcome(outcome) {
109
117
  if (status === "sent") {
110
118
  return typeof id === "string" && id !== "" ? { status, id } : { status: "unavailable" };
111
119
  }
112
- if (status === "rejected" || status === "unavailable") {
113
- return typeof httpStatus === "number" ? { status, httpStatus } : { status };
120
+ if (typeof status === "string" && Object.hasOwn(FAILURE_CODES, status)) {
121
+ const failure = status;
122
+ return isHttpStatus(httpStatus) ? { status: failure, httpStatus } : { status: failure };
114
123
  }
115
124
  return { status: "unavailable" };
116
125
  }
126
+ function isHttpStatus(value) {
127
+ return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599;
128
+ }
117
129
  /**
118
130
  * The module's only log line. Deliberately takes nothing but the provider, the code, a status,
119
131
  * field names and a fixed cause: anything added "for diagnosis" is where an address leaks first.
@@ -1 +1 @@
1
- {"version":3,"file":"send-mail.js","sourceRoot":"","sources":["../../src/server/send-mail.ts"],"names":[],"mappings":"AAAA,kGAAkG;AAClG,iGAAiG;AACjG,mGAAmG;AACnG,kGAAkG;AAClG,8FAA8F;AAC9F,OAAO,EAAE,GAAG,EAAE,EAAE,EAAsB,MAAM,kBAAkB,CAAC;AAE/D,OAAO,EAAE,kBAAkB,EAAsJ,MAAM,gBAAgB,CAAC;AAExM,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC7I,OAAO,EAAE,YAAY,EAAkB,MAAM,oBAAoB,CAAC;AAalE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,OAAoB,EAAE,IAAkB,EAAE,UAA2B,EAAE;IACpG,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEjF,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;QACnB,UAAU,CAAC,QAAQ,EAAE,uBAAuB,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7E,OAAO,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC;IAC9D,IAAI,OAAO,GAAgB,OAAO,CAAC;IACnC,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;QAClE,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,UAAU,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;YAChE,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC3B,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,EAAE,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,cAAc,EAAE,EAAE,SAAS,CAAC,CAAC;IACxH,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,MAAM,IAAI,GAAqB,WAAW,OAAO,CAAC,MAAM,EAAE,CAAC;IAC3D,UAAU,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAC3D,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC;AAMD;;;GAGG;AACH,KAAK,UAAU,eAAe,CAAC,OAAoB,EAAE,IAAe;IAClE,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,8FAA8F,CAAC,CAAC;IAClH,CAAC;IACD,MAAM,MAAM,GAAG,sBAAsB,EAAE,CAAC,OAAO,CAAC;IAChD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,4BAA4B,sBAAsB,cAAc,MAAM,CAAC,6BAA6B,CAAC,wCAAwC,CAAC,CAAC;QAC7J,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;IACrF,CAAC;IACD,IAAI,UAAmB,CAAC;IACxB,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,+EAA+E;QAC/E,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;IACvF,CAAC;IACD,IAAI,UAAU;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAEzF,MAAM,KAAK,GAAG,qBAAqB,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACrE,+EAA+E;IAC/E,MAAM,IAAI,GAAI,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAqB,CAAC,MAAM,CAAC;IAC1G,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE;YACL,EAAE,EAAE,IAAI,CAAC,EAAE;YACX,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC;YAC3C,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC;YACvE,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,yBAAyB,CAAC,KAAK,CAAC,EAAE;SAClE;KACF,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,YAAY,CAAC,QAAsB,EAAE,OAA4C,EAAE,SAAiB;IACjH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,IAAI,KAAgD,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAkB,CAAC,OAAO,EAAE,EAAE;QACvD,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,UAAU,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,8CAA8C,EAAE,cAAc,CAAC,CAAC,CAAC;YACnG,OAAO,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC;QACrC,CAAC,EAAE,SAAS,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,QAAQ;SACrB,IAAI,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;SAC5C,IAAI,CAAC,WAAW,EAAE,GAAoB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IACzE,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IAChD,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC;AAED,kGAAkG;AAClG,SAAS,WAAW,CAAC,OAAgB;IACnC,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IACtF,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,OAAmE,CAAC;IACvG,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAC1F,CAAC;IACD,IAAI,MAAM,KAAK,UAAU,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QACtD,OAAO,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9E,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,SAAS,UAAU,CACjB,QAAsB,EACtB,IAAsB,EACtB,OAAmG;IAEnG,MAAM,KAAK,GAAG,CAAC,YAAY,QAAQ,CAAC,IAAI,EAAE,EAAE,UAAU,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,UAAU,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACnK,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACnF,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,IAAI,CAAC,SAAS,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IACtE,OAAO,CAAC,KAAK,CAAC,wBAAwB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"send-mail.js","sourceRoot":"","sources":["../../src/server/send-mail.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { type ModuleContext, type Result } from "@softure-ai/core";
2
2
  import type { Queryable } from "@softure-ai/db";
3
3
  import type { SuppressionSource, UnsubscribeErrorCode } from "../contract.js";
4
- import { type Env, type UnsubscribeToken } from "./unsubscribe-link.js";
4
+ import { type Env, type UnsubscribeLink, type UnsubscribeToken } from "./unsubscribe-link.js";
5
5
  export type SuppressionContext = ModuleContext<Queryable>;
6
6
  /** Whether `address` unsubscribed. Throws on a database failure: callers decide how to fail. */
7
7
  export declare function isSuppressed(ctx: Pick<SuppressionContext, "db">, address: string): Promise<boolean>;
@@ -18,10 +18,12 @@ export declare function suppressRecipient(ctx: SuppressionContext, address: stri
18
18
  */
19
19
  export declare function liftSuppression(ctx: Pick<SuppressionContext, "db">, address: string): Promise<boolean>;
20
20
  /**
21
- * Unsubscribes the recipient of a signed link and runs `onUnsubscribed` in the same transaction,
22
- * also when the recipient had already unsubscribed (a retried one-click heals a missed hook). The
23
- * signature is checked before the database is touched; a link that does not verify is
24
- * `mailing.invalid_link`. Throws on a database failure or when the hook throws (nothing is stored).
21
+ * Unsubscribes the recipient of a link and runs `onUnsubscribed` in the same transaction, also when
22
+ * the recipient had already unsubscribed (a retried one-click heals a missed hook). A signed link
23
+ * (or a bare token) is checked against the secrets before the database is touched; a legacy link
24
+ * goes to the app's `legacyUnsubscribe.verify`, which names the address. A link that does not
25
+ * verify is `mailing.invalid_link`. Throws on a database failure, or when `verify` or the hook
26
+ * throws (nothing is stored).
25
27
  */
26
- export declare function unsubscribe(ctx: SuppressionContext, token: UnsubscribeToken | null, source: Exclude<SuppressionSource, "operator">, env?: Env): Promise<Result<undefined, UnsubscribeErrorCode>>;
28
+ export declare function unsubscribe(ctx: SuppressionContext, link: UnsubscribeLink | UnsubscribeToken | null, source: Exclude<SuppressionSource, "operator">, env?: Env): Promise<Result<undefined, UnsubscribeErrorCode>>;
27
29
  //# sourceMappingURL=suppressions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"suppressions.d.ts","sourceRoot":"","sources":["../../src/server/suppressions.ts"],"names":[],"mappings":"AAKA,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG9E,OAAO,EAAmE,KAAK,GAAG,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzI,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;AAE1D,gGAAgG;AAChG,wBAAsB,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOzG;AAOD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,iBAA8B,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvI;AAKD;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAM5G;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,kBAAkB,EACvB,KAAK,EAAE,gBAAgB,GAAG,IAAI,EAC9B,MAAM,EAAE,OAAO,CAAC,iBAAiB,EAAE,UAAU,CAAC,EAC9C,GAAG,GAAE,GAAiB,GACrB,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC,CAUlD"}
1
+ {"version":3,"file":"suppressions.d.ts","sourceRoot":"","sources":["../../src/server/suppressions.ts"],"names":[],"mappings":"AAKA,OAAO,EAAW,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG9E,OAAO,EAAmE,KAAK,GAAG,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE/J,MAAM,MAAM,kBAAkB,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;AAE1D,gGAAgG;AAChG,wBAAsB,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOzG;AAOD;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,iBAA8B,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvI;AAKD;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAM5G;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,kBAAkB,EACvB,IAAI,EAAE,eAAe,GAAG,gBAAgB,GAAG,IAAI,EAC/C,MAAM,EAAE,OAAO,CAAC,iBAAiB,EAAE,UAAU,CAAC,EAC9C,GAAG,GAAE,GAAiB,GACrB,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC,CAUlD"}
@@ -44,16 +44,18 @@ export async function liftSuppression(ctx, address) {
44
44
  return lifted.length > 0;
45
45
  }
46
46
  /**
47
- * Unsubscribes the recipient of a signed link and runs `onUnsubscribed` in the same transaction,
48
- * also when the recipient had already unsubscribed (a retried one-click heals a missed hook). The
49
- * signature is checked before the database is touched; a link that does not verify is
50
- * `mailing.invalid_link`. Throws on a database failure or when the hook throws (nothing is stored).
47
+ * Unsubscribes the recipient of a link and runs `onUnsubscribed` in the same transaction, also when
48
+ * the recipient had already unsubscribed (a retried one-click heals a missed hook). A signed link
49
+ * (or a bare token) is checked against the secrets before the database is touched; a legacy link
50
+ * goes to the app's `legacyUnsubscribe.verify`, which names the address. A link that does not
51
+ * verify is `mailing.invalid_link`. Throws on a database failure, or when `verify` or the hook
52
+ * throws (nothing is stored).
51
53
  */
52
- export async function unsubscribe(ctx, token, source, env = process.env) {
53
- if (token === null || !verifyUnsubscribeToken(token, readUnsubscribeSecrets(env)))
54
+ export async function unsubscribe(ctx, link, source, env = process.env) {
55
+ const recipientKey = await verifyLink(ctx, link, env);
56
+ if (recipientKey === null)
54
57
  return err("mailing.invalid_link");
55
58
  const { onUnsubscribed } = getMailingOptions(ctx.config);
56
- const { recipientKey } = token;
57
59
  await ctx.db.transaction(async (tx) => {
58
60
  const txCtx = { ...ctx, db: tx };
59
61
  await recordSuppression(txCtx, recipientKey, source);
@@ -61,4 +63,18 @@ export async function unsubscribe(ctx, token, source, env = process.env) {
61
63
  });
62
64
  return ok();
63
65
  }
66
+ /** The recipient key a link proves, or `null` when it proves none. */
67
+ async function verifyLink(ctx, link, env) {
68
+ if (link === null)
69
+ return null;
70
+ if (!("scheme" in link) || link.scheme === "signed") {
71
+ const token = "scheme" in link ? link.token : link;
72
+ return verifyUnsubscribeToken(token, readUnsubscribeSecrets(env)) ? token.recipientKey : null;
73
+ }
74
+ const legacy = getMailingOptions(ctx.config).legacyUnsubscribe;
75
+ if (legacy === undefined)
76
+ return null;
77
+ const address = await legacy.verify(link.values, ctx);
78
+ return typeof address === "string" && address.trim() !== "" ? getRecipientKey(address) : null;
79
+ }
64
80
  //# sourceMappingURL=suppressions.js.map