mailauth 5.0.1 → 5.0.2

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.
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "5.0.1"
2
+ ".": "5.0.2"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [5.0.2](https://github.com/postalsys/mailauth/compare/v5.0.1...v5.0.2) (2026-08-19)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **spf:** expand %{d} macro to the domain currently being evaluated ([#126](https://github.com/postalsys/mailauth/issues/126)) ([53c4522](https://github.com/postalsys/mailauth/commit/53c45220a1af41febb5b901c251ed4cc66de511e))
9
+
3
10
  ## [5.0.1](https://github.com/postalsys/mailauth/compare/v5.0.0...v5.0.1) (2026-08-07)
4
11
 
5
12
 
package/lib/spf/macro.js CHANGED
@@ -12,11 +12,12 @@ const os = require('node:os');
12
12
  * @param {String} values.ip Sender IP address
13
13
  * @param {String} values.helo Client's HELO/EHLO domain
14
14
  * @param {String} [values.mta] Hostname of the MTA or MX server that processes the message
15
+ * @param {String} [values.domain] Domain currently being evaluated by check_host(), changes on include/redirect recursion (RFC 7208 sections 5.2, 6.1)
15
16
  */
16
17
  const macro = (input, values) => {
17
18
  input = (input || '').toString();
18
19
 
19
- let { sender, ip, helo, mta } = values || {};
20
+ let { sender, ip, helo, mta, domain } = values || {};
20
21
 
21
22
  sender = (sender || '').toString();
22
23
  ip = (ip || '').toString();
@@ -64,11 +65,15 @@ const macro = (input, values) => {
64
65
  break;
65
66
 
66
67
  case 'o':
67
- case 'd':
68
68
  case 'p': // validated domain name is unsupported, instead we use the unvalidated sender domain
69
69
  curval = senderDomain;
70
70
  break;
71
71
 
72
+ case 'd':
73
+ // current <domain> of check_host(), not the sender domain (these only match at the top level)
74
+ curval = domain || senderDomain;
75
+ break;
76
+
72
77
  case 'i':
73
78
  curval = ipaddr.parse(ip).toNormalizedString();
74
79
  if (net.isIPv6(ip)) {
@@ -72,6 +72,9 @@ const spfVerify = async (domain, opts) => {
72
72
 
73
73
  let addr = ipaddr.parse(opts.ip);
74
74
 
75
+ // %{d} must expand to the domain currently being evaluated, which changes on include/redirect recursion
76
+ let macroValues = { sender: opts.sender, ip: opts.ip, helo: opts.helo, mta: opts.mta, domain };
77
+
75
78
  let resolver = opts.resolver || dns.resolve;
76
79
 
77
80
  let responses;
@@ -135,7 +138,7 @@ const spfVerify = async (domain, opts) => {
135
138
  let modifier = part.substr(0, splitPos).toLowerCase();
136
139
  let value = part.substr(splitPos + 1);
137
140
 
138
- value = macro(value, opts)
141
+ value = macro(value, macroValues)
139
142
  // remove trailing dot
140
143
  .replace(/\.$/, '');
141
144
 
@@ -254,7 +257,7 @@ const spfVerify = async (domain, opts) => {
254
257
  case 'include':
255
258
  {
256
259
  try {
257
- let redirect = macro(val, opts)
260
+ let redirect = macro(val, macroValues)
258
261
  // remove trailing dot
259
262
  .replace(/\.$/, '');
260
263
  let sub = await spfVerify(redirect, opts);
@@ -328,7 +331,7 @@ const spfVerify = async (domain, opts) => {
328
331
  let { domain: a, cidr4, cidr6 } = parseCidrValue(val, domain, type);
329
332
  let cidr = net.isIPv6(opts.ip) ? cidr6 : cidr4;
330
333
 
331
- a = macro(a, opts);
334
+ a = macro(a, macroValues);
332
335
 
333
336
  try {
334
337
  a = punycode.toASCII(a);
@@ -354,7 +357,7 @@ const spfVerify = async (domain, opts) => {
354
357
  let { domain: mxDomain, cidr4, cidr6 } = parseCidrValue(val, domain, type);
355
358
  let cidr = net.isIPv6(opts.ip) ? cidr6 : cidr4;
356
359
 
357
- mxDomain = macro(mxDomain, opts);
360
+ mxDomain = macro(mxDomain, macroValues);
358
361
 
359
362
  try {
360
363
  mxDomain = punycode.toASCII(mxDomain);
@@ -397,7 +400,7 @@ const spfVerify = async (domain, opts) => {
397
400
 
398
401
  case 'exists':
399
402
  {
400
- let existDomain = macro(val, opts);
403
+ let existDomain = macro(val, macroValues);
401
404
  try {
402
405
  existDomain = punycode.toASCII(existDomain);
403
406
  } catch (err) {
@@ -420,12 +423,8 @@ const spfVerify = async (domain, opts) => {
420
423
  throw err;
421
424
  }
422
425
 
423
- let ptrDomain;
424
- if (val) {
425
- ptrDomain = macro(val, opts);
426
- } else {
427
- ptrDomain = macro('%{d}', opts);
428
- }
426
+ // bare "ptr" defaults to %{d}, the currently evaluated domain
427
+ let ptrDomain = val ? macro(val, macroValues) : domain;
429
428
  ptrDomain = formatDomain(ptrDomain);
430
429
 
431
430
  // Step 1. Resolve PTR hostnames
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mailauth",
3
- "version": "5.0.1",
3
+ "version": "5.0.2",
4
4
  "description": "Email authentication library for Node.js",
5
5
  "main": "lib/mailauth.js",
6
6
  "types": "index.d.ts",