GithubHelp home page GithubHelp logo

postalsys / mailauth Goto Github PK

View Code? Open in Web Editor NEW
126.0 8.0 10.0 70.91 MB

Command line utility and a Node.js library for email authentication

License: Other

JavaScript 100.00%
dkim arc dmarc spf email mta-sts bimi mailauth

mailauth's People

Contributors

andris9 avatar github-actions[bot] avatar niftylettuce avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mailauth's Issues

mailauth depends on a vulnerable library

Latest mailauth depends on a vulnerable library, please provide an update.

# npm audit report
fast-xml-parser  <4.2.4
Severity: high
fast-xml-parser vulnerable to Regex Injection via Doctype Entities - https://github.com/advisories/GHSA-6w63-h3fj-q4vw
fix available via `npm audit fix --force`
Will install [email protected], which is a breaking change
node_modules/fast-xml-parser
  mailauth  >=3.0.2
  Depends on vulnerable versions of fast-xml-parser
  node_modules/mailauth

Expose `getDmarcRecord` and `getSpfRecord`

Right now getDmarcRecord could easily be exposed via exports or module.exports.

However there's no getSpfRecord, albeit one could be added similarly with a returned object including values such as qualifier.

SPF check of domains containing the MX mechanism

Describe the bug
I think but I'm not entirely sure the SPF tester is unhappy with domain names having MX records pointing at uppercase mail exchange hostnames

To Reproduce
Steps to reproduce the behavior:

Testing SPF record validity on a domain like: vgpt.dk
results in this error:
permanent error in processing during lookup of [email protected]: Invalid domain ASPMX.L.GOOGLE.COM)\r\n

dig vgpt.dk MX
vgpt.dk. 3505 IN MX 5 ALT1.ASPMX.L.GOOGLE.COM.
vgpt.dk. 3505 IN MX 5 ALT2.ASPMX.L.GOOGLE.COM.
vgpt.dk. 3505 IN MX 10 ALT3.ASPMX.L.GOOGLE.COM.
vgpt.dk. 3505 IN MX 1 ASPMX.L.GOOGLE.COM.
vgpt.dk. 3505 IN MX 10 ALT4.ASPMX.L.GOOGLE.COM.

Expected behavior
Uppercase mail exchanger hostnames should not be an issue

Bug: `body hash did not verify`

I think that this might only occur with large bodies (e.g. messages that get forwarded/replied to etc).

Our usage is here, and we apply and verify a signature from our side (not dependent on a third party).

Here's where we use mailauth to sign and then verify:

https://github.com/forwardemail/forwardemail.net/blob/2c5db33457ab33b1439516eca5e17a3158924f1e/helpers/process-email.js#L454-L574

Any idea what might be wrong @andris9?

Here's what dkim variable output is from above linked code for this case where body hash did not verify occurs:

{
  "id": "97d0704fa6532ffc464d91848bfff529c3a7901418f6a5ae96c4da743aea78eb",
  "signingDomain": "redacted.com",
  "selector": "fe-redacted",
  "signature": "xOsyw/9QxTmDGWSe3pqI/a+JA+KvDCleqTKmzQxpB5ABrvq0ywEjBAd4W4YqbwJLaN5TDOC6KIZJqKPLPHKb83KyIUrPXtw84Ecv7D+1OOVeZDBjUW4GoykQFYuSAFGBpjSwENu3mva5D5aN6rEHkhi9KIUmPt4GdZAWBErnVFY=",
  "algo": "rsa-sha256",
  "format": "relaxed/relaxed",
  "bodyHash": "MEyQD56x/T6mAyiOCf9Wb3Bbv+F5uc5F2JyGTfkYXiY=",
  "bodyHashExpecting": "nNcD0wNn1JDvNR4xBIDnXZfySkjnkuY9D6YZ/PaDeJI=",
  "signingHeaders": {
    "keys": "Content-Type: To: Subject: Message-ID: Date: From: Reply-To: In-Reply-To: References: MIME-Version",
    "headers": [
      "Content-Type: multipart/alternative; boundary=\"000000000000d28675061495178e\"",
      "To: redacted",
      "Subject: Re: Redacted",
      "Message-ID: <[email protected]>",
      "Date: Tue, 26 Mar 2024 15:13:51 -0400",
      "From: redacted redacted <[email protected]>",
      "Reply-To: [email protected]",
      "In-Reply-To: <[email protected]>",
      "References: <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]>\r\n <[email protected]> <[email protected]>",
      "MIME-Version: 1.0"
    ],
    "canonicalizedHeader": "Y29udGVudC10eXBlOm11bHRpcGFydC9hbHRlcm5hdGl2ZTsgYm91bmRhcnk9IjAwMDAwMDAwMDAwMGQyODY3NTA2MTQ5NTE3OGUiDQp0bzpDaGFudGVsIER1cHVpcyA8Y2hhbnRlbC5kdXB1aXNAZGl2ZXJzaWNvLmNhPg0Kc3ViamVjdDpSZTogUkVTUCBJbmZvcm1hdGlvbg0KbWVzc2FnZS1pZDo8Q0FPVWNyZmZ1KzhNOUZRU3ZiYVRBNGJfNHNvOXZfNmtpZ09WPVNwRktTQi1xRHRaaUV3QG1haWwuZ21haWwuY29tPg0KZGF0ZTpUdWUsIDI2IE1hciAyMDI0IDE1OjEzOjUxIC0wNDAwDQpmcm9tOkdhcnkgQmVsYW5nZXIgPGdhcnlAYmVsYW5nZXJob21lLmNvbT4NCnJlcGx5LXRvOmdhcnlAYmVsYW5nZXJob21lLmNvbQ0KaW4tcmVwbHktdG86PENBTHN2WkVZb1pIV2hrd1lvdERFZ0c1V09xM2U5c1NBPWErRHVaQnBZU1BKdjZRdHBmd0BtYWlsLmdtYWlsLmNvbT4NCnJlZmVyZW5jZXM6PENBTHN2WkVac2dmRWlEKzVwYVc5K09reE9QVEc5YVMwRzYtcGJNblI9XzBIRUpZNXE0QUBtYWlsLmdtYWlsLmNvbT4gPENBQTNxU0VGdUZMLVhBZFE4a3NlemEwTEV1VC01TE0wUkpGTmNZdD1VUndpZEpCRkNwUUBtYWlsLmdtYWlsLmNvbT4gPENBTHN2WkVZU3M1VitVeV9aNk5WNExZLXJzdFRLVmJFWDVTYW9xQTRpWGM2enJ5Wjk5d0BtYWlsLmdtYWlsLmNvbT4gPENBQTNxU0VIbWJtazFrUGYzWVF4anRHYzRzbk1NSFA3YXdBcEJFYnVHZVpoUHY3TlBfd0BtYWlsLmdtYWlsLmNvbT4gPENBTHN2WkViK1pFTGgyZk1ISnRnWE95Y2lnWjl5c2kzWXpXdHJ3d3J0ZWlTUGkwY1NFd0BtYWlsLmdtYWlsLmNvbT4gPENBQTNxU0VIV2Z6b2hCZzNVM2QyS282NTVMTnBzVzJVNG5RdEdzYjNWZ3ctOGVWV25WQUBtYWlsLmdtYWlsLmNvbT4gPENBTHN2WkViNjBqVU5NOWk9S3JwM2lubWt0ZVBNR2dRb2pmYT1BelZPeUNXTjMzaW9pQUBtYWlsLmdtYWlsLmNvbT4gPENBQTNxU0VHVkhLNkhjQyt4NHB2K2RTNisrcmtFVldieFY2dm01cHM3NVNhN3grZGdld0BtYWlsLmdtYWlsLmNvbT4gPENBTHN2WkViN1VBcWQ4RGRLRU5xNWpvb2RxXzIzWVV3TXhVUFFYVldqdWFHMzRnMllmUUBtYWlsLmdtYWlsLmNvbT4gPENBQTNxU0VIdFRKZFJQTzFwNnErYndPSDJQME1talprRTRFSEtHa3ZUVlVPOV8xdkw1Z0BtYWlsLmdtYWlsLmNvbT4gPENBTHN2WkVhUzBtOT15ZStPclBaMGZnUD1tODIzV3hET01OOVZCdE1pU249Wkc3R1pld0BtYWlsLmdtYWlsLmNvbT4gPENBQTNxU0VGVzltbWtQeVZYUGZjREV3ZXE3QmhqYUFveFhkVjViTUdZNnE0Y1VEV3NqQUBtYWlsLmdtYWlsLmNvbT4gPENBTHN2WkVZNjZ2b29OVmVvQV9rZHpFenJBdU8yMjE5cnZ1LV9RM3ZqeVRtNDcxUD0yZ0BtYWlsLmdtYWlsLmNvbT4gPENBQTNxU0VFM0FSU1h6bl82Q0EyVllYNDB5U1VvRWM0Z19VZUNqRit3Yys9MWY1QUZpZ0BtYWlsLmdtYWlsLmNvbT4gPENBTHN2WkVZR0FHakM3eHpXWVFQY2lZNlYrTlVkVHErYWlkZGtmQjgzWk5oPXp3SnRkUUBtYWlsLmdtYWlsLmNvbT4gPENBT1VjcmZkRFpqLWQ0UHdTYTJBS1EyTU1FcTRZYjljdFpyZkZoT1g5QmRoN0MySlROQUBtYWlsLmdtYWlsLmNvbT4gPENBTHN2WkVZb1pIV2hrd1lvdERFZ0c1V09xM2U5c1NBPWErRHVaQnBZU1BKdjZRdHBmd0BtYWlsLmdtYWlsLmNvbT4NCm1pbWUtdmVyc2lvbjoxLjANCmRraW0tc2lnbmF0dXJlOnY9MTsgYT1yc2Etc2hhMjU2OyBjPXJlbGF4ZWQvcmVsYXhlZDsgZD1iZWxhbmdlcmhvbWUuY29tOyBoPUNvbnRlbnQtVHlwZTogVG86IFN1YmplY3Q6IE1lc3NhZ2UtSUQ6IERhdGU6IEZyb206IFJlcGx5LVRvOiBJbi1SZXBseS1UbzogUmVmZXJlbmNlczogTUlNRS1WZXJzaW9uOyBxPWRucy90eHQ7IHM9ZmUtZWE5NjlmNmYxMDsgdD0xNzExNjY0Nzg3OyBiaD1uTmNEMHdObjFKRHZOUjR4QklEblhaZnlTa2pua3VZOUQ2WVovUGFEZUpJPTsgYj0="
  },
  "status": {
    "result": "neutral",
    "comment": "body hash did not verify",
    "header": {
      "i": "@redacted.com",
      "s": "fe-redacted",
      "a": "rsa-sha256",
      "b": "xOsyw/9Q"
    },
    "aligned": "redacted.com"
  },
  "sourceBodyLength": 94578,
  "canonBodyLength": 94314,
  "canonBodyLengthTotal": 94314,
  "canonBodyLengthLimited": false,
  "mimeStructureStart": 0,
  "info": "dkim=neutral (body hash did not verify) [email protected] header.s=fe-redacted header.a=rsa-sha256 header.b=\"xOsyw/9Q\""
}

`psl` does not return valid org domains (unmaintained project)

DMARC lookups are not returning accurate data right now due to the psl library being used.

An example use case is a headerFrom of [email protected].

> require('psl').get('pay-dartford-crossing-fine.service.gov.uk')
'pay-dartford-crossing-fine.service.gov.uk'

Since it is not returning service.gov.uk in the psl.get('pay-dartford-crossing-fine.service.gov.uk') invocation, the orgDomain is not being properly looked up and therefore the DMARC policy returned is none, when it should actually be this one:

❯ dig _dmarc.service.gov.uk txt
_dmarc.service.gov.uk.	1124	IN	TXT	"v=DMARC1; p=reject; sp=reject; fo=1; rua=mailto:[email protected]; ruf=mailto:[email protected]"

We are submitting a pull request now to swap out psl in favor of a different more maintained project.

Cloudflare workers support

Is your feature request related to a problem? Please describe.
I would like to use mailauth in a Cloudflare Worker, it's currently not possible

Describe the solution you'd like
mailauth uses XMLHttpRequest, this is not supported by Cloudflare workers, they use fetch instead

mailauth depends an a package with a known security vulnerability (undici)

mailauth depends an a package with a known security vulnerability.

# npm audit report

undici  <5.26.2
Undici's cookie header not cleared on cross-origin redirect in fetch - https://github.com/advisories/GHSA-wqq4-5wpv-mx2g
fix available via `npm audit fix --force`
Will install [email protected], which is a breaking change
node_modules/undici
  mailauth  >=4.5.1
  Depends on vulnerable versions of undici
  node_modules/mailauth

Steps to reproduce the behavior:

  1. npm install mailauth && npm audit

SPF macros - DNS response includes invalid characters

 dig +short TXT officedepot.com | grep spf

"v=spf1 include:%{i}._ip.%{h}._ehlo.%{d}._spf.vali.email ~all"
dig +short TXT 205.157.110.125._ip.odmailout01.officedepot.com._ehlo.officedepot.com._spf.vali.email

"v=spf1 ip4:205.157.110.125 -all"

It looks like macros aren't supported by this library or standard Node.js DNS lookups?

DOS when performing DKIM-validation of email

Hello!

Encountered CPU stuck at 100% on all our inbound email microservices fleet this night and morning, for a repeated number of times after manual NodeJS process restarts probably due to SMTP delivery retries.

The issue seems to be a DOS, which was traced to origin in mailauth DKIM module after performing a Node profile (--prof), here's the trace extract from the processed profile:

   ticks parent  name
  813252   88.5%  /usr/lib/x86_64-linux-gnu/libc.so.6
  755301   92.9%    JS: *fixLineBuffer /app/node_modules/mailauth/lib/dkim/body/relaxed.js:125:18
  755299  100.0%      JS: *update /app/node_modules/mailauth/lib/dkim/body/relaxed.js:169:11
  755297  100.0%        JS: *processChunk /app/node_modules/mailauth/lib/dkim/message-parser.js:40:23
  755291  100.0%          JS: ^writeAsync /app/node_modules/mailauth/lib/dkim/message-parser.js:112:21
  755291  100.0%            JS: ^_write /app/node_modules/mailauth/lib/dkim/message-parser.js:128:11

  96000   10.4%  UNKNOWN
  60769   63.3%    JS: *fixLineBuffer /app/node_modules/mailauth/lib/dkim/body/relaxed.js:125:18
  60761  100.0%      JS: *update /app/node_modules/mailauth/lib/dkim/body/relaxed.js:169:11
  60751  100.0%        JS: *processChunk /app/node_modules/mailauth/lib/dkim/message-parser.js:40:23
  60718   99.9%          JS: ^writeAsync /app/node_modules/mailauth/lib/dkim/message-parser.js:112:21
  60718  100.0%            JS: ^_write /app/node_modules/mailauth/lib/dkim/message-parser.js:128:11
   1144    1.2%    JS: *isSignature /app/node_modules/email-reply-parser/lib/parser/emailparser.js:143:14
   1144  100.0%      JS: ^<anonymous> /app/node_modules/email-reply-parser/lib/parser/emailparser.js:43:50
   1144  100.0%        JS: ^parse /app/node_modules/email-reply-parser/lib/parser/emailparser.js:37:8
   1144  100.0%          JS: ^read /app/node_modules/email-reply-parser/lib/emailreplyparser.js:4:9
   1144  100.0%            JS: ^<anonymous> /app/src/helpers/parser.js:1491:15
   1083    1.1%    JS: ^createPublicKey node:internal/crypto/keys:611:25
   1082   99.9%      JS: ^getPublicKey /app/node_modules/mailauth/lib/tools.js:237:22
    841   77.7%        JS: *processTicksAndRejections node:internal/process/task_queues:67:35
    241   22.3%        JS: ^processTicksAndRejections node:internal/process/task_queues:67:35

When tracing the code, there appears to be some O(n^2) algorithm involved here (no Regex, this does not appear to be a ReDOS to me): https://github.com/postalsys/mailauth/blob/master/lib/dkim/body/relaxed.js#L212

I unfortunately do not have the original mail data which triggered this possible DOS vulnerability, since we do not keep a record of emails that went through before processing them. I'm trying to obtain the email content now.

SPF DNS lookup limit capabilities

the RFC for SPF defines a DNS lookup limit of 10. It seems like the current SPF validation check does not detect that.

Describe the solution you'd like
Have a correct SPF softfail if there are over 10 lookups. Also, it would be great to have

  1. an option to arbitrarily change the lookup limit to more than 10 for testing.
  2. The validation result to report on how many DNS lookups were used

https://github.com/mediamonks/node-spf-check is an older project that has some code related to handling lookup limits.

spf for ipv6

spf({
    sender: '[email protected]',
    ip: '2607:f8b0:4864:20::b2b',
    helo: 'mail-yb1-xb2b.google.com',
    mta: 'mta.mydomain.com'
  }).then((sr) => {
      console.log(sr)
  }).catch(e=>{

  });

this giving result as softfail? i think it should be pass
i also tried wrapping ip inside [ ] it gives neutral

Used node-forge has a security vulnerability

Describe the bug

The used node-forge package has a security vulnerability. While the code in question may not be triggered by mailauth, the vulnerable module breaks out CI/CD process. Please upgrade node-forge:

$ npm audit --production
# npm audit report
node-forge  <1.3.0
Severity: moderate
Improper Verification of Cryptographic Signature in `node-forge` - https://github.com/advisories/GHSA-2r2c-g63r-vccr
No fix available
node_modules/mailauth/node_modules/node-forge
  mailauth  *
  Depends on vulnerable versions of node-forge
  node_modules/mailauth
2 moderate severity vulnerabilities
Some issues need review, and may require choosing
a different dependency.

What are your problems replacing node-forge with webcrypto completely?

RR field not returned for some SPF records

Describe the bug
When the SPF check is performed on certain domains the "rr" field is not set.

To Reproduce
Perform an SPF check on bimco.org

Expected behavior
Valid SPF records (rr field) should always be returned

Timeout

Describe the bug
Not really bug, just a question, and I couldn't find another way to contact you.
Is there a way to configure DNS timeout values?

From time to time, I detect invalid SPF records, and if I try again, the issue is gone.

DNS timeouts are the only reason I can think of.

Return the list of signed headers with other results.

Is your feature request related to a problem? Please describe.
After checking a DKIM signature and finding that results.status.result === "pass" how can I find out what headers were signed?
I would like to know which headers I can now trust, and which I might treat with skepticism.

Describe the solution you'd like
I would like the list of headers returned.

Describe alternatives you've considered
The alternative is for me to search for and parse this signature myself, I guess.

Additional context

feat: add SPF PTR support (since Yahoo still uses)

We're writing as we discovered an edge case where vacation auto-responders from Yahoo would normally have passing SPF and DKIM (thus a passing DMARC), but when using mailauth, not only do we get a negative DMARC result, we also get a negative SPF and DKIM result too. Gmail for example reports these vacation response messages from Yahoo as having passing DMARC, DKIM, and SPF.

We've included a complete test for you as well so you can see the result.

mailauth --verbose --client-ip 66.163.189.147 --sender [email protected] --helo sonic314-21.consmr.mail.ne1.yahoo.com --mta mx1.forwardemail.net test.txt
Reading email message from test.txt
{
  "dkim": {
    "headerFrom": [
      "[email protected]"
    ],
    "envelopeFrom": "[email protected]",
    "results": [
      {
        "signingDomain": "yahoo.com",
        "selector": "s2048",
        "signature": "U6xSIk/z+xTpR2vRhfKVn9ONotJWf2WTvroxSg5/kCtQ+zxcvUdCaH80Py+Cz7TtieCy77/kRqFzpJTp1R1OJf+m9TeS2DUaijVM8RKdbmHmZhRY6/YwKyJdhj9+9z6y7jVcxqS+7+ib+wqipOKE5Q6p87zLlXfOXgYsFh/Bott86PFmf5sKhf1C/LkmPreJE4ep21AU7NM4zaTLhY8fS2fdKDDXq2cyaE8LKu9CkWCcUaMqmFJ11GQetDZvCD5nBIR89GvM8IAWmPWWFGSD7c1AJcOC51+1ILcfsg8IqPhLUPpDPsRbT2Z31LI9clxlPvaI6yRanTnj0Cf3LJ5UIQ==",
        "algo": "rsa-sha256",
        "format": "relaxed/relaxed",
        "bodyHash": "mD4IKcP0SaNBDF959LqTWtanj/53dx+DHlUfLpHedO4=",
        "bodyHashExpecting": "mD4IKcP0SaNBDF959LqTWtanj/53dx+DHlUfLpHedO4=",
        "signingHeaders": {
          "keys": "Date: From: To: Subject",
          "headers": [
            "Date: Fri, 29 Jul 2022 19:22:11 +0000 (UTC)",
            "From: Forwared Email <[email protected]>",
            "To: <[email protected]>",
            "Subject: Auto Response: Attempt to show failure"
          ]
        },
        "status": {
          "result": "fail",
          "header": {
            "i": "@yahoo.com",
            "s": "s2048",
            "a": "rsa-sha256",
            "b": "U6xSIk/z"
          },
          "aligned": "yahoo.com"
        },
        "canonBodyLength": 371,
        "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoWufgbWw58MczUGbMv1\n76RaxdZGOMkQmn8OOJ/HGoQ6dalSMWiLaj8IMcHC1cubJx2gziAPQHVPtFYayyLA\n4ayJUSNk10/uqfByiU8qiPCE4JSFrpxflhMIKV4bt+g1uHw7wLzguCf4YAoR6XxU\nKRsAoHuoF7M+v6bMZ/X1G+viWHkBl4UfgJQ6O8F1ckKKoZ5KqUkJH5pDaqbgs+F3\nPpyiAUQfB6EEzOA1KMPRWJGpzgPtKoukDcQuKUw9GAul7kSIyEcizqrbaUKNLGAm\nz0elkqRnzIsVpz6jdT1/YV5Ri6YUOQ5sN5bqNzZ8TxoQlkbVRy6eKOjUnoSSTmSA\nhwIDAQAB\n-----END PUBLIC KEY-----",
        "modulusLength": 2048,
        "rr": "k=rsa;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuoWufgbWw58MczUGbMv176RaxdZGOMkQmn8OOJ/HGoQ6dalSMWiLaj8IMcHC1cubJx2gziAPQHVPtFYayyLA4ayJUSNk10/uqfByiU8qiPCE4JSFrpxflhMIKV4bt+g1uHw7wLzguCf4YAoR6XxUKRsAoHuoF7M+v6bMZ/X1G+viWHkBl4UfgJQ6O8F1ckKKoZ5KqUkJH5pDaqbgs+F3PpyiAUQfB6EEzOA1KMPRWJGpzgPtKoukDcQuKUw9GAul7kSIyEcizqrbaUKNLGAmz0elkqRnzIsVpz6jdT1/YV5Ri6YUOQ5sN5bqNzZ8TxoQlkbVRy6eKOjUnoSSTmSAhwIDAQAB;",
        "info": "dkim=fail [email protected] header.s=s2048 header.a=rsa-sha256 header.b=\"U6xSIk/z\""
      }
    ]
  },
  "spf": {
    "domain": "yahoo.com",
    "client-ip": "66.163.189.147",
    "helo": "sonic314-21.consmr.mail.ne1.yahoo.com",
    "envelope-from": "[email protected]",
    "rr": "v=spf1 redirect=_spf.mail.yahoo.com",
    "status": {
      "result": "neutral",
      "comment": "mx1.forwardemail.net: 66.163.189.147 is neither permitted nor denied by domain of [email protected]",
      "smtp": {
        "mailfrom": "[email protected]",
        "helo": "sonic314-21.consmr.mail.ne1.yahoo.com"
      }
    },
    "header": "Received-SPF: neutral (mx1.forwardemail.net: 66.163.189.147 is neither permitted nor denied by domain of [email protected]) client-ip=66.163.189.147;",
    "info": "spf=neutral (mx1.forwardemail.net: 66.163.189.147 is neither permitted nor denied by domain of [email protected]) [email protected] smtp.helo=sonic314-21.consmr.mail.ne1.yahoo.com",
    "lookups": {
      "limit": 50,
      "count": 2
    }
  },
  "dmarc": {
    "status": {
      "result": "fail",
      "comment": "p=REJECT arc=none",
      "header": {
        "from": "yahoo.com",
        "d": "yahoo.com"
      }
    },
    "domain": "yahoo.com",
    "policy": "reject",
    "p": "reject",
    "sp": "reject",
    "pct": 100,
    "rr": "v=DMARC1; p=reject; pct=100; rua=mailto:[email protected]; ruf=mailto:[email protected];",
    "alignment": {
      "spf": {
        "result": false,
        "strict": false
      },
      "dkim": {
        "result": false,
        "strict": false
      }
    },
    "info": "dmarc=fail (p=REJECT arc=none) header.from=yahoo.com header.d=yahoo.com"
  },
  "arc": {
    "status": {
      "result": "none"
    },
    "i": 0,
    "authResults": "mx1.forwardemail.net;\r\n dkim=fail [email protected] header.s=s2048 header.a=rsa-sha256 header.b=\"U6xSIk/z\";\r\n spf=neutral (mx1.forwardemail.net: 66.163.189.147 is neither permitted nor denied by domain of [email protected])\r\n [email protected] smtp.helo=sonic314-21.consmr.mail.ne1.yahoo.com;\r\n dmarc=fail (p=REJECT arc=none) header.from=yahoo.com header.d=yahoo.com;\r\n bimi=skipped (message failed DMARC)"
  },
  "bimi": {
    "status": {
      "header": {},
      "result": "skipped",
      "comment": "message failed DMARC"
    },
    "info": "bimi=skipped (message failed DMARC)"
  },
  "receivedChain": [
    {
      "from": {
        "value": "sonic.gate.mail.ne1.yahoo.com"
      },
      "by": {
        "value": "sonic314.consmr.mail.ne1.yahoo.com"
      },
      "with": {
        "value": "HTTP"
      },
      "timestamp": "Fri, 29 Jul 2022 19:22:11 +0000",
      "full": "Received: from sonic.gate.mail.ne1.yahoo.com by sonic314.consmr.mail.ne1.yahoo.com with HTTP; Fri, 29 Jul 2022 19:22:11 +0000"
    }
  ],
  "headers": "Received-SPF: neutral (mx1.forwardemail.net: 66.163.189.147 is neither permitted nor denied by domain of [email protected]) client-ip=66.163.189.147;\r\nAuthentication-Results: mx1.forwardemail.net;\r\n dkim=fail [email protected] header.s=s2048 header.a=rsa-sha256 header.b=\"U6xSIk/z\";\r\n spf=neutral (mx1.forwardemail.net: 66.163.189.147 is neither permitted nor denied by domain of [email protected])\r\n [email protected] smtp.helo=sonic314-21.consmr.mail.ne1.yahoo.com;\r\n dmarc=fail (p=REJECT arc=none) header.from=yahoo.com header.d=yahoo.com;\r\n bimi=skipped (message failed DMARC)\r\n"
}

Contents of test-new.eml are attached: test.txt

BIMI standards compliancy

BIMI spec

  • if DMARC p=none or pct<100 then reject BIMI
  • if subdomain does not have BIMI set, resolve using main domain
  • show Authority Evidence Location URL in result if available
  • if a=; and l=; then reject BIMI for subdomain even if main domain has it set

TypeScript types

Is your feature request related to a problem? Please describe.

Currently, it's hard to know what properties are available on the result object and there is no type safety when using TypeScript.

Describe the solution you'd like

I'd love to have TypeScript types either shipped with the package or published under @types/

Describe alternatives you've considered

Typing everything as any :)

Additional context

I tried writing types with some AI help from the example JSON: https://gist.githubusercontent.com/andris9/6514b5e7c59154a5b08636f99052ce37/raw/a6fa78c400fd7068de502e878f0da1eb9334cd7b/mailauth.json

It seems that is currently the only documentation of what properties are available?
Unfortunately I don't know nearly enough about the internals of the library and all the email specs to know which properties should be optional/required etc so some help would be greatly appreciated — even if in the form of written API documentation (list of fields and types) or JSDoc. It would also be nice to add descriptions for the fields. I'd be happy to help writing types from that.

Here's what I got with AI help (which unfortunately still has some type errors with the result JSON):

export interface EmailAuthenticationResult {
  dkim: DKIM
  spf: SPF
  dmarc: DMARC
  arc: ARC
  bimi: BIMI
  headers: string
}

export interface DKIM {
  headerFrom: string[]
  envelopeFrom: string
  results: DKIMResult[]
}

export interface DKIMResult {
  signingDomain: string
  selector: string
  signature: string
  algo: string
  format: string
  bodyHash: string
  bodyHashExpecting: string
  status: DKIMStatus
  publicKey: string
  info: string
}

export interface DKIMStatus {
  result: string
  comment?: boolean
  header: DKIMHeader
  policy?: Record<string, unknown>
  aligned: string | boolean
}

export interface DKIMHeader {
  i: string
  s: string
  a: string
  b: string
}

export interface SPF {
  domain: string
  "client-ip": string
  helo: string
  "envelope-from": string
  status: SPFStatus
  header: string
  info: string
}

export interface SPFStatus {
  result: string
  comment: string
  smtp: SPFSMTP
}

export interface SPFSMTP {
  mailfrom: string
  helo: string
}

export interface DMARC {
  status: DMARCStatus
  domain: string
  policy: string
  p: string
  sp: string
  info: string
}

export interface DMARCStatus {
  result: string
  comment: string
  header: DMARCHeader
}

export interface DMARCHeader {
  from: string
}

export interface ARC {
  status: ARCStatus
  i: number
  signature: ARCSignature
  authenticationResults: ARCResults
  info: string
  authResults: string
}

export interface ARCStatus {
  result: string
  comment: string | boolean
}

export interface ARCSignature {
  signingDomain: string
  selector: string
  signature: string
  algo: string
  format: string
  bodyHash: string
  bodyHashExpecting: string
  status: ARCStatus // Reusing ARCStatus as it matches the structure
  publicKey: string
}

export interface ARCResults {
  [key: string]: ARCResult | ARCDKIM[] | SPF // key is the domain, e.g., "mx.google.com"
}

export interface ARCResult {
  value: string
}

export interface ARCDKIM {
  header: DKIMHeader
  result: string
}

export interface BIMI {
  status: BIMIStatus
  location: string
  info: string
}

export interface BIMIStatus {
  header: BIMIHeader
  result: string
}

export interface BIMIHeader {
  selector: string
  d: string
}

SPF policies with an exists method fail (considered as having no SPF policy at all)

Hey @andris9, thank you so much for your work on mailauth. I'd frandkly have built this library myself if you did not do it first, thanks again for that.

I'm using mailauth on a busy inbound mail server, successfully, however I'm seeing instances where SPF validation fails, with the following eg. output:

digitalocean.com does not designate permitted sender hosts

Checking digitalocean.com manually, it appears that their SPF policy is valid. Note that I've raised the DNS resolution limit from 10 to 20 just to be safe, as they are well above the 10 resolutions limit.

Their policy is as such:

"v=spf1 include:spf.digitalocean.com include:_spf.google.com include:_spf.salesforce.com include:mg-spf.greenhouse.io include:helpscoutemail.com -all"

When digging _spf.salesforce.com, it appears that they are using the SPF exists method:

"v=spf1 exists:%{i}._spf.mta.salesforce.com -all"

I got the very same error for the siemens.com domain name, which has a valid (though huge) SPF policy, and which is also using the exists method:

"v=spf1 exists:%{i}.spf.siemens.com include:spf.protection.outlook.com include:amazonses.com include:all.spf.avature.net include:mail.zendesk.com -all"

It appears that SPF results containing the following pattern: exists:%{i} lead to mailauth thinking that there is no SPF policy at all on the domain.

question about temperror in spf

hi @andris9 Thanks for your great libraries,

if a domain dns server does not return any TXT record does that mean we should always get temperror ?
in the result object i am getting status as temperror , in comment dns error code ENODATA

Invalid relaxed DKIM body hash if the message ens with mixed whitespace and newlines

DKIM relaxed body hash calculation should trim all whitespace and newlines from the end of the email. Instead it trims starting from the last line that has at least one whitespace byte

Header\r\n
\r\n
Trims correctly\r\n
\r\n
\r\n
\r\n

-->

Header\r\n
\r\n
Trims correctly\r\n
Header\r\n
\r\n
Does not trim correctly\r\n
\r\n
\t\r\n
\r\n

-->

Header\r\n
\r\n
Does not trim correctly\r\n
\r\n

No RR returned if default mechanish is missing

Describe the bug
The RR field is not returned for SPF records where the default mechanism is missing

To Reproduce

mailauth spf -f bellcom.dk -i 1.2.3.4
{
"domain": "bellcom.dk",
"client-ip": "1.2.3.4",
"envelope-from": "[email protected]",
"status": {
"result": "neutral",
"comment": "STL-R7N4H9RQF6: 1.2.3.4 is neither permitted nor denied by domain of [email protected]",
"smtp": {
"mailfrom": "[email protected]"
}
},
"header": "Received-SPF: neutral (STL-R7N4H9RQF6: 1.2.3.4 is neither permitted nor denied by domain of [email protected]) client-ip=1.2.3.4;",
"info": "spf=neutral (STL-R7N4H9RQF6: 1.2.3.4 is neither permitted nor denied by domain of [email protected]) smtp.mailfrom=[email protected]"
}

However:
dig +short bellcom.dk txt
"v=spf1 include:_spf.bellcom.dk"
"google-site-verification: mrYNF5E8kEkNacSV-zrITF03H7FSh6-qTTki86F6k84"

Expected behavior
I think to remember the default mechanish is ?all (neutral), so while the record is sort of meaningless it is valid, and it would be nice if the RR field in the result was set.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.