{"_id":"@akiflow/mailauth","_rev":"3-b0f7a1ee52eda7396f690afb2a8b534e","name":"@akiflow/mailauth","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.1":{"name":"@akiflow/mailauth","version":"0.0.1","keywords":["rfc822","email","dkim","spf","arc","dmarc","bimi","mta-sts"],"author":{"name":"Postal Systems OÜ"},"license":"MIT","_id":"@akiflow/mailauth@0.0.1","maintainers":[{"name":"akiflowdevelopers","email":"developers@akiflow.com"},{"name":"andrei_akiflow","email":"andrei@akiflow.com"},{"name":"flydown","email":"extra@finotto.org"}],"homepage":"https://github.com/postalsys/mailauth","bugs":{"url":"https://github.com/postalsys/mailauth/issues"},"bin":{"mailauth":"bin/mailauth.js"},"pkg":{"assets":["licenses.txt","LICENSE.txt"],"targets":["node20-linux-x64","node20-macos-x64","node20-macos-arm64","node20-win-x64"],"outputPath":"ee-dist"},"dist":{"shasum":"243659a38c07b13f177dd4a8c17822e0087f743d","tarball":"https://registry.npmjs.org/@akiflow/mailauth/-/mailauth-0.0.1.tgz","fileCount":56,"integrity":"sha512-XoPTucVh3+wwcBuzCI4+HdnfxCEN6KJur2Np1U5fSj32XF3sqzg5iQDhTT6f4RE66bwmtFM+bJ2N6EiC0kToqw==","signatures":[{"sig":"MEUCIGAZJRQd3T8Rx1uSz6o+miOFPS0W6zpmi7Kr2xJUIXOaAiEAxKyTJGrVl6/W6NVDownPcyyR4Ng4A85Vosa4kuij0fc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":455483},"main":"lib/mailauth.js","engines":{"node":">=18.0.0"},"gitHead":"1a5b9bc2f3038f93345372378ba7949d1def18f6","scripts":{"test":"eslint \"lib/**/*.js\" \"test/**/*.js\" && mocha --recursive \"./test/**/*.js\" --reporter spec","update":"rm -rf node_modules package-lock.json && npx ncu -u && npm install","licenses":"license-report --only=prod --output=table --config license-report-config.json > licenses.txt","build-dist":"npx pkg --compress Brotli package.json && rm -rf package-lock.json && npm install && node winconf.js","build-source":"rm -rf node_modules package-lock.json && npm install && npm run licenses && rm -rf node_modules package-lock.json && npm install --production && rm -rf package-lock.json","build-dist-fast":"pkg --debug package.json && npm install && node winconf.js"},"_npmUser":{"name":"akiflowdevelopers","email":"developers@akiflow.com"},"repository":{"url":"git+https://github.com/postalsys/mailauth.git","type":"git"},"_npmVersion":"10.8.2","description":"Email authentication library for Node.js","directories":{},"_nodeVersion":"20.19.3","dependencies":{"joi":"17.13.3","tldts":"7.0.7","yargs":"17.7.2","undici":"7.10.0","libmime":"5.3.6","ipaddr.js":"2.2.0","nodemailer":"7.0.3","punycode.js":"2.3.1","@postalsys/vmc":"1.1.2","fast-xml-parser":"4.5.2"},"_hasShrinkwrap":false,"devDependencies":{"chai":"4.4.1","mocha":"11.5.0","eslint":"8.56.0","js-yaml":"4.1.0","resedit":"^2.0.3","mbox-reader":"1.2.0","license-report":"6.7.2","eslint-config-prettier":"9.1.0","eslint-config-nodemailer":"1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/mailauth_0.0.1_1753375061364_0.9388360633923194","host":"s3://npm-registry-packages-npm-production"}},"0.0.2":{"name":"@akiflow/mailauth","version":"0.0.2","keywords":["rfc822","email","dkim","spf","arc","dmarc","bimi","mta-sts"],"author":{"name":"Postal Systems OÜ"},"license":"MIT","_id":"@akiflow/mailauth@0.0.2","maintainers":[{"name":"akiflowdevelopers","email":"developers@akiflow.com"},{"name":"andrei_akiflow","email":"andrei@akiflow.com"},{"name":"flydown","email":"extra@finotto.org"}],"homepage":"https://github.com/postalsys/mailauth","bugs":{"url":"https://github.com/postalsys/mailauth/issues"},"bin":{"mailauth":"bin/mailauth.js"},"pkg":{"assets":["licenses.txt","LICENSE.txt"],"targets":["node20-linux-x64","node20-macos-x64","node20-macos-arm64","node20-win-x64"],"outputPath":"ee-dist"},"dist":{"shasum":"399f2d31033984f64b9a6033f0602bb11c6dc826","tarball":"https://registry.npmjs.org/@akiflow/mailauth/-/mailauth-0.0.2.tgz","fileCount":56,"integrity":"sha512-m98cJrqktnPv6x5F4YZ3Pq9ULmhCHE4H77MbgPb1K1i0rkbf+y/+7lOEz+FJ2kTbuzeLJJvkizAV7NOXr98iOA==","signatures":[{"sig":"MEUCIQDt4jky8wGvhiJXyjZH3z1LUqdFp6ZYiKpb63aKQ0bgLQIgMc2HyNw2qQAgLhcKLwQt/MIGFWHwMYfu+mlFb7PtqVs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":456456},"main":"lib/mailauth.js","engines":{"node":">=18.0.0"},"gitHead":"8bc4fb9b00db5584d7dbd9855a496ced9df41013","scripts":{"test":"eslint \"lib/**/*.js\" \"test/**/*.js\" && mocha --recursive \"./test/**/*.js\" --reporter spec","update":"rm -rf node_modules package-lock.json && npx ncu -u && npm install","licenses":"license-report --only=prod --output=table --config license-report-config.json > licenses.txt","build-dist":"npx pkg --compress Brotli package.json && rm -rf package-lock.json && npm install && node winconf.js","build-source":"rm -rf node_modules package-lock.json && npm install && npm run licenses && rm -rf node_modules package-lock.json && npm install --production && rm -rf package-lock.json","build-dist-fast":"pkg --debug package.json && npm install && node winconf.js"},"_npmUser":{"name":"akiflowdevelopers","email":"developers@akiflow.com"},"repository":{"url":"git+https://github.com/postalsys/mailauth.git","type":"git"},"_npmVersion":"10.8.2","description":"Email authentication library for Node.js","directories":{},"_nodeVersion":"20.19.3","dependencies":{"joi":"17.13.3","tldts":"7.0.7","yargs":"17.7.2","undici":"7.10.0","libmime":"5.3.6","ipaddr.js":"2.2.0","nodemailer":"7.0.3","punycode.js":"2.3.1","@postalsys/vmc":"1.1.2","fast-xml-parser":"4.5.2"},"_hasShrinkwrap":false,"devDependencies":{"chai":"4.4.1","mocha":"11.5.0","eslint":"8.56.0","js-yaml":"4.1.0","resedit":"^2.0.3","mbox-reader":"1.2.0","license-report":"6.7.2","eslint-config-prettier":"9.1.0","eslint-config-nodemailer":"1.2.0"},"_npmOperationalInternal":{"tmp":"tmp/mailauth_0.0.2_1753376483763_0.9777536233517279","host":"s3://npm-registry-packages-npm-production"}}},"time":{"created":"2025-07-24T16:37:41.261Z","modified":"2026-03-24T15:53:18.416Z","0.0.1":"2025-07-24T16:37:41.603Z","0.0.2":"2025-07-24T17:01:23.965Z"},"bugs":{"url":"https://github.com/postalsys/mailauth/issues"},"author":{"name":"Postal Systems OÜ"},"license":"MIT","homepage":"https://github.com/postalsys/mailauth","keywords":["rfc822","email","dkim","spf","arc","dmarc","bimi","mta-sts"],"repository":{"url":"git+https://github.com/postalsys/mailauth.git","type":"git"},"description":"Email authentication library for Node.js","maintainers":[{"email":"developers@akiflow.com","name":"akiflowdevelopers"},{"email":"andrei@akiflow.com","name":"andrei_akiflow"},{"email":"extra@finotto.org","name":"flydown"},{"email":"gherardo@akiflow.com","name":"akidon"}],"readme":"## Fork by akiflow\nThis fork is made to support right cases for the `crypto.verify` function as we are running the package on bun, which expect different cases for the algorithm parameter.\n\nThis has been reported to original package (https://github.com/postalsys/mailauth/issues/91) and to the Bun team as well (https://github.com/oven-sh/bun/issues/21354).\n\nUnfortuantely, we couldn't find a way to reliably list the supported algorithms with the right case, especially in Bun, \nso we will resort to execute the verify twice with different cases for the algorithm parameter.\n\n# mailauth: Email Authentication for Node.js\n\n![mailauth Logo](https://github.com/postalsys/mailauth/raw/master/assets/mailauth.png)\n\n**mailauth** is a comprehensive Node.js library and command-line utility for email authentication. It provides tools to work with various email security protocols, including SPF, DKIM, DMARC, ARC, BIMI, and MTA-STS. With mailauth, you can verify and sign emails, handle authentication results, and enhance your email security setup.\n\n**Key Features:**\n\n-   **SPF** verification\n-   **DKIM** signing and verification\n-   **DMARC** verification\n-   **ARC** verification and sealing\n    -   Sealing during authentication\n    -   Sealing after message modifications\n-   **BIMI** resolving and **VMC** validation\n-   **MTA-STS** helper functions\n\nmailauth is a pure JavaScript implementation, requiring no external applications or compilation. It runs on any server or device with Node.js version 16 or later.\n\n## Table of Contents\n\n1. [Installation](#installation)\n2. [Command-Line Usage](#command-line-usage)\n3. [Library Usage](#library-usage)\n    - [Authentication](#authentication)\n    - [DKIM](#dkim)\n        - [Signing](#dkim-signing)\n        - [Verification](#dkim-verification)\n    - [SPF](#spf)\n        - [Verification](#spf-verification)\n    - [ARC](#arc)\n        - [Validation](#arc-validation)\n        - [Sealing](#arc-sealing)\n    - [DMARC](#dmarc)\n        - [Helpers](#dmarc-helpers)\n    - [BIMI](#bimi)\n    - [MTA-STS](#mta-sts)\n        - [Policy Retrieval](#policy-retrieval)\n        - [MX Validation](#mx-validation)\n4. [Testing](#testing)\n5. [License](#license)\n\n## Installation\n\nFirst, install mailauth from npm:\n\n```bash\nnpm install mailauth\n```\n\nThen, import the desired methods into your script:\n\n```javascript\nconst { authenticate } = require('mailauth');\n```\n\n## Command-Line Usage\n\nmailauth includes a command-line utility called `mailauth`. For detailed information on how to use it, see the [command-line documentation](cli.md).\n\n## Library Usage\n\n### Authentication\n\nUse the `authenticate` function to validate DKIM signatures, SPF, DMARC, ARC, and BIMI for an email.\n\n#### Syntax\n\n```javascript\nawait authenticate(message [, options])\n// Returns: { dkim, spf, arc, dmarc, bimi, receivedChain, headers }\n```\n\n#### Parameters\n\n-   **message**: A `String`, `Buffer`, or `Readable` stream representing the email message.\n-   **options** (optional):\n    -   **sender** (`string`): Email address from the MAIL FROM command. Defaults to the `Return-Path` header if not set.\n    -   **ip** (`string`): IP address of the remote client that sent the message.\n    -   **helo** (`string`): Hostname from the HELO/EHLO command.\n    -   **trustReceived** (`boolean`): If `true`, parses `ip` and `helo` from the latest `Received` header if not provided. Defaults to `false`.\n    -   **mta** (`string`): Hostname of the server performing the authentication. Defaults to `os.hostname()`. Included in Authentication headers.\n    -   **minBitLength** (`number`): Minimum allowed bits for RSA public keys. Defaults to `1024`. Keys with fewer bits will fail validation.\n    -   **disableArc** (`boolean`): If `true`, skips ARC checks.\n    -   **disableDmarc** (`boolean`): If `true`, skips DMARC checks, also disabling dependent checks like BIMI.\n    -   **disableBimi** (`boolean`): If `true`, skips BIMI checks.\n    -   **seal** (`object`): Options for ARC sealing if the message doesn't have a broken ARC chain.\n        -   **signingDomain** (`string`): ARC key domain name.\n        -   **selector** (`string`): ARC key selector.\n        -   **privateKey** (`string` or `Buffer`): Private key for signing (RSA or Ed25519).\n    -   **resolver** (`async function`): Custom DNS resolver function. Defaults to [`dns.promises.resolve`](https://nodejs.org/api/dns.html#dns_dnspromises_resolve_hostname_rrtype).\n    -   **maxResolveCount** (`number`): DNS lookup limit for SPF. Defaults to `10` as per [RFC7208](https://datatracker.ietf.org/doc/html/rfc7208#section-4.6.4).\n    -   **maxVoidCount** (`number`): DNS lookup limit for SPF producing empty results. Defaults to `2` as per [RFC7208](https://datatracker.ietf.org/doc/html/rfc7208#section-4.6.4).\n\n#### Example\n\n```javascript\nconst { authenticate } = require('mailauth');\nconst dns = require('dns');\n\nconst message = /* Your email message here */;\n\nconst { dkim, spf, arc, dmarc, bimi, receivedChain, headers } = await authenticate(message, {\n  // SMTP transmission options\n  ip: '217.146.67.33',                 // SMTP client IP\n  helo: 'uvn-67-33.tll01.zonevs.eu',   // HELO/EHLO hostname\n  sender: 'andris@ekiri.ee',           // MAIL FROM address\n\n  // Uncomment to parse `ip` and `helo` from the latest `Received` header\n  // trustReceived: true,\n\n  // Server performing the authentication\n  mta: 'mx.ethereal.email',\n\n  // Optional DNS resolver function\n  resolver: async (name, rr) => await dns.promises.resolve(name, rr),\n});\n\n// Output authenticated message\nprocess.stdout.write(headers); // Includes terminating line break\nprocess.stdout.write(message);\n```\n\n**Sample Output:**\n\n```\nReceived-SPF: pass (mx.ethereal.email: domain of andris@ekiri.ee designates 217.146.67.33 as permitted sender) client-ip=217.146.67.33;\nAuthentication-Results: mx.ethereal.email;\n dkim=pass header.i=@ekiri.ee header.s=default header.a=rsa-sha256 header.b=TXuCNlsq;\n spf=pass (mx.ethereal.email: domain of andris@ekiri.ee designates 217.146.67.33 as permitted sender) smtp.mailfrom=andris@ekiri.ee\n smtp.helo=uvn-67-33.tll01.zonevs.eu;\n arc=pass (i=2 spf=neutral dkim=pass dkdomain=ekiri.ee);\n dmarc=none header.from=ekiri.ee\nFrom: ...\n```\n\nYou can see the full output, including structured data for DKIM, SPF, DMARC, and ARC, from [this example](https://gist.github.com/andris9/6514b5e7c59154a5b08636f99052ce37).\n\n**Note:** The `receivedChain` property is an array of parsed representations of the `Received:` headers.\n\n### DKIM\n\n#### DKIM Signing\n\nUse the `dkimSign` function to sign an email message with DKIM.\n\n##### Syntax\n\n```javascript\nconst { dkimSign } = require('mailauth/lib/dkim/sign');\n\nconst signResult = await dkimSign(message, options);\n// Returns: { signatures: String, errors: Array }\n```\n\n##### Parameters\n\n-   **message**: A `String`, `Buffer`, or `Readable` stream representing the email message.\n-   **options**:\n    -   **canonicalization** (`string`): Canonicalization method. Defaults to `'relaxed/relaxed'`.\n    -   **algorithm** (`string`): Signing and hashing algorithm. Defaults to `'rsa-sha256'`.\n    -   **signTime** (`Date`): Signing time. Defaults to current time.\n    -   **signatureData** (`Array`): Array of signature objects. Each object may contain:\n        -   **signingDomain** (`string`): DKIM key domain name.\n        -   **selector** (`string`): DKIM key selector.\n        -   **privateKey** (`string` or `Buffer`): Private key for signing (RSA or Ed25519).\n        -   **algorithm** (`string`, optional): Overrides parent `algorithm`.\n        -   **canonicalization** (`string`, optional): Overrides parent `canonicalization`.\n        -   **maxBodyLength** (`number`, optional): Maximum number of canonicalized body bytes to sign (`l=` tag). Not recommended for general use.\n\n##### Example\n\n```javascript\nconst { dkimSign } = require('mailauth/lib/dkim/sign');\nconst fs = require('fs');\n\nconst message = /* Your email message here */;\n\nconst signResult = await dkimSign(message, {\n  canonicalization: 'relaxed/relaxed',\n  algorithm: 'rsa-sha256',\n  signTime: new Date(),\n  signatureData: [\n    {\n      signingDomain: 'tahvel.info',\n      selector: 'test.rsa',\n      privateKey: fs.readFileSync('./test/fixtures/private-rsa.pem'),\n    },\n  ],\n});\n\n// Display signing errors if any\nif (signResult.errors.length) {\n  console.error('Signing errors:', signResult.errors);\n}\n\n// Output signed message\nprocess.stdout.write(signResult.signatures); // Includes terminating line break\nprocess.stdout.write(message);\n```\n\n**Sample Output:**\n\n```\nDKIM-Signature: a=rsa-sha256; v=1; c=relaxed/relaxed; d=tahvel.info;\n s=test.rsa; b=...\nFrom: ...\n```\n\n#### DKIM Signing as a Stream\n\nUse `DkimSignStream` to sign messages as part of a stream processing pipeline.\n\n##### Example\n\n```javascript\nconst { DkimSignStream } = require('mailauth/lib/dkim/sign');\nconst fs = require('fs');\n\nconst dkimSignStream = new DkimSignStream({\n    canonicalization: 'relaxed/relaxed',\n    algorithm: 'rsa-sha256',\n    signTime: new Date(),\n    signatureData: [\n        {\n            signingDomain: 'tahvel.info',\n            selector: 'test.rsa',\n            privateKey: fs.readFileSync('./test/fixtures/private-rsa.pem')\n        }\n    ]\n});\n\n// Read from stdin, write signed message to stdout\nprocess.stdin.pipe(dkimSignStream).pipe(process.stdout);\n```\n\n#### DKIM Verification\n\nUse the `dkimVerify` function to verify DKIM signatures in an email message.\n\n##### Syntax\n\n```javascript\nconst { dkimVerify } = require('mailauth/lib/dkim/verify');\n\nconst result = await dkimVerify(message);\n// Returns an object containing verification results\n```\n\n##### Example\n\n```javascript\nconst { dkimVerify } = require('mailauth/lib/dkim/verify');\n\nconst message = /* Your email message here */;\n\nconst result = await dkimVerify(message);\n\nfor (const { info } of result.results) {\n  console.log(info);\n}\n```\n\n**Sample Output:**\n\n```\ndkim=neutral (invalid public key) header.i=@tahvel.info header.s=test.invalid header.b=\"b85yao+1\"\ndkim=pass header.i=@tahvel.info header.s=test.rsa header.b=\"BrEgDN4A\"\ndkim=policy policy.dkim-rules=weak-key header.i=@tahvel.info header.s=test.small header.b=\"d0jjgPun\"\n```\n\n### SPF\n\n#### SPF Verification\n\nUse the `spf` function to verify the SPF record for an email sender.\n\n##### Syntax\n\n```javascript\nconst { spf } = require('mailauth/lib/spf');\n\nconst result = await spf(options);\n// Returns an object containing SPF verification results\n```\n\n##### Parameters\n\n-   **options**:\n    -   **sender** (`string`): MAIL FROM address.\n    -   **ip** (`string`): SMTP client IP.\n    -   **helo** (`string`): HELO/EHLO hostname.\n    -   **mta** (`string`): Hostname of the MTA performing the check.\n\n##### Example\n\n```javascript\nconst { spf } = require('mailauth/lib/spf');\n\nconst result = await spf({\n    sender: 'andris@wildduck.email',\n    ip: '217.146.76.20',\n    helo: 'foo',\n    mta: 'mx.myhost.com'\n});\n\nconsole.log(result.header);\n```\n\n**Sample Output:**\n\n```\nReceived-SPF: pass (mx.myhost.com: domain of andris@wildduck.email\n designates 217.146.76.20 as permitted sender) client-ip=217.146.76.20;\n envelope-from=\"andris@wildduck.email\";\n```\n\n### ARC\n\n#### ARC Validation\n\nARC seals are validated automatically during the authentication step.\n\n##### Example\n\n```javascript\nconst { authenticate } = require('mailauth');\n\nconst message = /* Your email message here */;\n\nconst { arc } = await authenticate(message, {\n  trustReceived: true,\n});\n\nconsole.log(arc);\n```\n\n**Sample Output:**\n\n```json\n{\n    \"status\": {\n        \"result\": \"pass\",\n        \"comment\": \"i=2 spf=neutral dkim=pass dkdomain=zonevs.eu dkim=pass dkdomain=srs3.zonevs.eu dmarc=fail fromdomain=zone.ee\"\n    },\n    \"i\": 2\n    // Additional properties...\n}\n```\n\n#### ARC Sealing\n\nYou can seal messages with ARC either during authentication or after modifications.\n\n##### Sealing During Authentication\n\nProvide the sealing key in the options to seal messages automatically during authentication.\n\n```javascript\nconst { authenticate } = require('mailauth');\nconst fs = require('fs');\n\nconst message = /* Your email message here */;\n\nconst { headers } = await authenticate(message, {\n  trustReceived: true,\n  seal: {\n    signingDomain: 'tahvel.info',\n    selector: 'test.rsa',\n    privateKey: fs.readFileSync('./test/fixtures/private-rsa.pem'),\n  },\n});\n\n// Output authenticated and sealed message\nprocess.stdout.write(headers); // Includes terminating line break\nprocess.stdout.write(message);\n```\n\n##### Sealing After Modifications\n\nIf you need to modify the message before sealing, first authenticate it, modify as needed, then seal using the authentication results.\n\n```javascript\nconst { authenticate, sealMessage } = require('mailauth');\nconst fs = require('fs');\n\nconst message = /* Your email message here */;\n\n// Step 1: Authenticate the message\nconst { arc, headers } = await authenticate(message, {\n  ip: '217.146.67.33',\n  helo: 'uvn-67-33.tll01.zonevs.eu',\n  mta: 'mx.ethereal.email',\n  sender: 'andris@ekiri.ee',\n});\n\n// Step 2: Modify the message as needed\n// ... your modifications ...\n\n// Step 3: Seal the modified message\nconst sealHeaders = await sealMessage(message, {\n  signingDomain: 'tahvel.info',\n  selector: 'test.rsa',\n  privateKey: fs.readFileSync('./test/fixtures/private-rsa.pem'),\n  authResults: arc.authResults,\n  cv: arc.status.result,\n});\n\n// Output the sealed message\nprocess.stdout.write(sealHeaders); // ARC headers\nprocess.stdout.write(headers);     // Authentication results\nprocess.stdout.write(message);\n```\n\n### DMARC\n\nDMARC is verified during the authentication process. Although the `dmarc` handler is exported, it requires input from previous steps like SPF and DKIM.\n\n#### DMARC Helpers\n\n##### `getDmarcRecord(domain [, resolver])`\n\nFetches and parses the DMARC DNS record for a domain or subdomain. Returns `false` if no record exists.\n\n###### Syntax\n\n```javascript\nconst getDmarcRecord = require('mailauth/lib/dmarc/get-dmarc-record');\n\nconst dmarcRecord = await getDmarcRecord(domain [, resolver]);\n// Returns an object with DMARC record details or `false` if not found\n```\n\n###### Parameters\n\n-   **domain** (`string`): The domain to check for a DMARC record.\n-   **resolver** (`function`, optional): Custom DNS resolver function. Defaults to `dns.resolve`.\n\n###### Example\n\n```javascript\nconst getDmarcRecord = require('mailauth/lib/dmarc/get-dmarc-record');\n\nconst dmarcRecord = await getDmarcRecord('ethereal.email');\nconsole.log(dmarcRecord);\n```\n\n**Sample Output:**\n\n```json\n{\n    \"v\": \"DMARC1\",\n    \"p\": \"none\",\n    \"pct\": 100,\n    \"rua\": \"mailto:re+joqy8fpatm3@dmarc.postmarkapp.com\",\n    \"sp\": \"none\",\n    \"aspf\": \"r\",\n    \"rr\": \"v=DMARC1; p=none; pct=100; rua=mailto:re+joqy8fpatm3@dmarc.postmarkapp.com; sp=none; aspf=r;\",\n    \"isOrgRecord\": false\n}\n```\n\n### BIMI\n\nBrand Indicators for Message Identification (BIMI) support is based on [draft-blank-ietf-bimi-02](https://tools.ietf.org/html/draft-blank-ietf-bimi-02). BIMI information is resolved during the authentication step, provided the message passes DMARC validation with a policy other than \"none\".\n\n#### Example\n\n```javascript\nconst { authenticate } = require('mailauth');\n\nconst message = /* Your email message here */;\n\nconst { bimi } = await authenticate(message, {\n  ip: '217.146.67.33',\n  helo: 'uvn-67-33.tll01.zonevs.eu',\n  mta: 'mx.ethereal.email',\n  sender: 'andris@ekiri.ee',\n  bimiWithAlignedDkim: false, // If true, ignores SPF in DMARC and requires a valid DKIM signature\n});\n\nif (bimi?.location) {\n  console.log(`BIMI location: ${bimi.location}`);\n}\n```\n\n**Note:**\n\n-   The `BIMI-Location` header is ignored by mailauth.\n-   The `BIMI-Selector` header can be used for selector selection if available.\n\n#### Verified Mark Certificate (VMC)\n\nIf an Authority Evidence Document is specified in the BIMI record, its location is available in `bimi.authority`. mailauth exposes the certificate type (`\"VMC\"` or `\"CMC\"`) in `bimi.authority.vmc.type`.\n\n**Example Authority Evidence Documents:**\n\n-   [CNN's VMC](https://amplify.valimail.com/bimi/time-warner/LysAFUdG-Hw-cnn_vmc.pem)\n-   [Entrust's VMC](https://www.entrustdatacard.com/-/media/certificate/Entrust%20VMC%20July%2014%202020.pem)\n\n### MTA-STS\n\nmailauth provides functions to fetch and validate MTA-STS policies for a domain.\n\n#### Policy Retrieval\n\nUse the `getPolicy` function to fetch the MTA-STS policy for a domain.\n\n##### Syntax\n\n```javascript\nconst { getPolicy } = require('mailauth/lib/mta-sts');\n\nconst { policy, status } = await getPolicy(domain [, knownPolicy]);\n// Returns an object with the policy and status\n```\n\n##### Parameters\n\n-   **domain** (`string`): The domain to retrieve the policy for.\n-   **knownPolicy** (`object`, optional): Previously cached policy for the domain.\n\n##### Example\n\n```javascript\nconst { getPolicy } = require('mailauth/lib/mta-sts');\n\nconst knownPolicy = /* Retrieve from your cache if available */;\nconst { policy, status } = await getPolicy('gmail.com', knownPolicy);\n\nif (policy.id !== knownPolicy?.id) {\n  // Update your cache with the new policy\n}\n\nif (policy.mode === 'enforce') {\n  // TLS must be used when sending to this domain\n}\n```\n\n**Possible Status Values:**\n\n-   `\"not_found\"`: No policy was found.\n-   `\"cached\"`: Existing policy is still valid.\n-   `\"found\"`: New or updated policy found.\n-   `\"renew\"`: Existing policy is valid; renew cache.\n-   `\"errored\"`: Policy discovery failed due to a temporary error.\n\n#### MX Validation\n\nUse the `validateMx` function to check if an MX hostname is valid according to the MTA-STS policy.\n\n##### Syntax\n\n```javascript\nconst { validateMx } = require('mailauth/lib/mta-sts');\n\nconst validation = validateMx(mx, policy);\n// Returns an object indicating if the MX is valid\n```\n\n##### Parameters\n\n-   **mx** (`string`): The resolved MX hostname.\n-   **policy** (`object`): The MTA-STS policy object.\n\n##### Example\n\n```javascript\nconst { getPolicy, validateMx } = require('mailauth/lib/mta-sts');\n\nconst { policy } = await getPolicy('gmail.com');\n\nconst mx = 'alt4.gmail-smtp-in.l.google.com';\nconst policyMatch = validateMx(mx, policy);\n\nif (policy.mx && !policyMatch.valid) {\n    // The MX host is not listed in the policy; do not connect\n}\n```\n\n## Testing\n\nmailauth uses the following test suites:\n\n### SPF Test Suite\n\nBased on the [OpenSPF test suite](http://www.openspf.org/Test_Suite), with some differences:\n\n-   Less strict whitespace checks.\n-   Some macro tests are skipped.\n-   Some tests are skipped where the invalid component is after a matching part.\n-   All other tests pass.\n\n### ARC Test Suite from ValiMail\n\nBased on ValiMail's [arc_test_suite](https://github.com/ValiMail/arc_test_suite):\n\n-   mailauth is less strict on header tags and casing.\n-   Signing test suite is used for input; mailauth validates signatures and checks for the same `cv=` output.\n-   All tests pass, aside from minor differences.\n\n## License\n\n&copy; 2020-2024 Postal Systems OÜ\n\nLicensed under the [MIT License](LICENSE).\n","readmeFilename":"README.md"}