1
2export const DKIM_SELECTORS = [
3
4 'google', '20230601', '20210112', '20161025',
5
6 'selector1', 'selector2',
7
8 's1', 's2', 'smtpapi',
9
10 'k1', 'k2', 'k3',
11
12 'smtp', 'mailo',
13
14 'protonmail', 'protonmail2', 'protonmail3',
15
16 'zmail',
17
18 'proofpoint', 'pfpt0220', 'pfpt0221', 'pfpt0222',
19
20 'mimecast20190307',
21
22 'fm1', 'fm2', 'fm3',
23
24 'sig1',
25
26 'cisco',
27
28 'hs1', 'hs2',
29
30 'sf', 'salesforce',
31
32 'ctct1', 'ctct2',
33
34 'default', 'dkim', 'email', 'mail',
35];
36
37
38
39
40
41export const PROVIDER_SPF_INCLUDES = {
42 'Google Workspace': ['_spf.google.com', 'google.com'],
43 'Microsoft 365': ['spf.protection.outlook.com', 'outlook.com'],
44 'Zoho Mail': ['zoho.com', 'zoho.eu'],
45 'ProtonMail': ['protonmail.ch', '_spf.protonmail.ch'],
46 'Fastmail': ['messagingengine.com'],
47 'Amazon SES': ['amazonses.com'],
48 'Yahoo Mail': ['yahoodns.net'],
49 'Rackspace Email': ['emailsrvr.com'],
50 'GoDaddy': ['secureserver.net'],
51 'iCloud Mail': ['icloud.com'],
52 'Namecheap/Titan': ['titan.email'],
53 'Yandex Mail': ['yandex.net', 'yandex.ru'],
54 'Migadu': ['migadu.com'],
55};
56
57
58
59export const SENDING_WEIGHTS = {
60 mx: 15,
61 spf: 15,
62 dkim: 15,
63 dmarc: 15,
64 blacklists: 15,
65 domainAge: 10,
66 ssl: 5,
67 dmarcReporting: 5,
68 reverseDns: 5,
69};
70
71
72export const RECEIVING_WEIGHTS = {
73 mx: 30,
74 domainResolves: 20,
75 disposable: 15,
76 domainAge: 15,
77 ssl: 20,
78};
79
80
81export const SENDING_SCORE_BANDS = [
82 { min: 90, band: 'Excellent', description: 'Fully configured. Strong email reputation.' },
83 { min: 75, band: 'Good', description: 'Minor improvements recommended.' },
84 { min: 50, band: 'Fair', description: 'Significant gaps. Fix before sending.' },
85 { min: 25, band: 'Poor', description: 'Major issues. Reputation at risk.' },
86 { min: 0, band: 'Critical', description: 'Unsafe. Likely unconfigured or compromised.' },
87];
88
89
90export const RECEIVING_SCORE_BANDS = [
91 { min: 90, band: 'Safe', description: 'High-confidence deliverable target.' },
92 { min: 70, band: 'Likely Safe', description: 'Minor risk factors present.' },
93 { min: 50, band: 'Risky', description: 'Young domain or missing infrastructure, limit volume.' },
94 { min: 0, band: 'Avoid', description: 'Cannot receive email or is disposable.' },
95];
96
97
98export const CRITICAL_SCORE_CAP = 40;
99
100
101export const SENDING_CRITICAL_FACTORS = ['mx', 'spf', 'dkim', 'blacklists'];
102
103
104export const RECEIVING_CRITICAL_FACTORS = ['mx', 'domainResolves', 'disposable'];
105
106
107export const SEVERITY = {
108 CRITICAL: 'critical',
109 WARNING: 'warning',
110 INFO: 'info',
111};
112
113
114export const ISSUES = {
115
116 NO_MX_RECORDS: { code: 'NO_MX_RECORDS', severity: 'critical', module: 'mx', message: 'Domain has no MX records. Cannot send or receive email.', impact: 'Email delivery is impossible without MX records.' },
117 MX_NO_RESOLVE: { code: 'MX_NO_RESOLVE', severity: 'critical', module: 'mx', message: 'MX record hostname does not resolve to an IP address.', impact: 'Mail servers cannot deliver to an MX host that does not resolve.' },
118 NO_SPF_RECORD: { code: 'NO_SPF_RECORD', severity: 'critical', module: 'spf', message: 'No SPF record found. SPF is required by Google, Yahoo, and Microsoft.', impact: 'Emails will fail authentication checks and may be rejected or sent to spam.' },
119 SPF_PLUS_ALL: { code: 'SPF_PLUS_ALL', severity: 'critical', module: 'spf', message: 'SPF record ends with +all, which authorizes the entire internet to send as your domain.', impact: 'Effectively no SPF protection. Any server can spoof your domain.' },
120 SPF_TOO_MANY_LOOKUPS: { code: 'SPF_TOO_MANY_LOOKUPS', severity: 'critical', module: 'spf', message: 'SPF record exceeds 10 DNS lookups. Results in PermError — authentication fails.', impact: 'Receiving servers will return a permanent error, treating SPF as if it does not exist.' },
121 MULTIPLE_SPF_RECORDS: { code: 'MULTIPLE_SPF_RECORDS', severity: 'critical', module: 'spf', message: 'Multiple v=spf1 TXT records found. Results in PermError.', impact: 'RFC 7208 requires exactly one SPF record. Multiple records cause authentication failure.' },
122 NO_DKIM_RECORD: { code: 'NO_DKIM_RECORD', severity: 'critical', module: 'dkim', message: 'No DKIM selectors found. DKIM is required by Google, Yahoo, and Microsoft.', impact: 'Emails will fail DKIM authentication and may be rejected or sent to spam.' },
123
124
125 NO_DMARC_RECORD: { code: 'NO_DMARC_RECORD', severity: 'warning', module: 'dmarc', message: 'No DMARC record found. DMARC is required by Google, Yahoo, and Microsoft.', impact: 'Without DMARC, receiving servers cannot enforce your SPF/DKIM policy.' },
126 DMARC_POLICY_NONE: { code: 'DMARC_POLICY_NONE', severity: 'warning', module: 'dmarc', message: "DMARC policy is set to 'none'. Upgrade to 'quarantine' or 'reject' for stronger protection.", impact: "Receiving servers treat p=none as monitoring-only. Spoofing protection is not enforced." },
127 DMARC_NO_RUA: { code: 'DMARC_NO_RUA', severity: 'warning', module: 'dmarc', message: 'No DMARC aggregate reporting address (rua=) configured.', impact: 'You cannot monitor who is sending email as your domain or detect authentication failures.' },
128 DKIM_KEY_1024: { code: 'DKIM_KEY_1024', severity: 'warning', module: 'dkim', message: 'DKIM key is 1024-bit. Upgrade to 2048-bit for better security.', impact: '1024-bit keys are still accepted but 2048-bit is the current recommendation.' },
129 DKIM_KEY_REVOKED: { code: 'DKIM_KEY_REVOKED', severity: 'warning', module: 'dkim', message: 'DKIM key has been revoked (empty p= tag).', impact: 'This selector can no longer be used for signing. Ensure another valid selector exists.' },
130 DKIM_UNVERIFIABLE: { code: 'DKIM_UNVERIFIABLE', severity: 'warning', module: 'dkim', message: 'DKIM selectors could not be discovered. Security gateway domains typically use custom selectors.', impact: 'DKIM is likely configured but uses non-standard selectors that cannot be verified through DNS probing.' },
131 SPF_DEPRECATED_PTR: { code: 'SPF_DEPRECATED_PTR', severity: 'warning', module: 'spf', message: 'SPF record uses deprecated ptr mechanism.', impact: 'The ptr mechanism is deprecated per RFC 7208 and may not be supported by all receivers.' },
132 SPF_MISSING_PROVIDER: { code: 'SPF_MISSING_PROVIDER', severity: 'warning', module: 'spf', message: 'SPF record does not include the detected email provider\'s SPF domain.', impact: 'Emails sent through your provider may fail SPF authentication.' },
133
134
135 SSL_MISSING: { code: 'SSL_MISSING', severity: 'warning', module: 'ssl', message: 'No SSL certificate found on port 443. HTTPS is unavailable.', impact: 'Browsers will show security warnings. Linked domains in emails may trigger spam filters.' },
136 SSL_EXPIRED: { code: 'SSL_EXPIRED', severity: 'warning', module: 'ssl', message: 'SSL certificate has expired.', impact: 'Browsers will block access with a security warning. Linked domains in emails may trigger spam filters.' },
137
138
139 DOMAIN_AGE_UNDER_7: { code: 'DOMAIN_AGE_UNDER_7', severity: 'critical', module: 'whois', message: 'Domain is less than 7 days old.', impact: 'Brand-new domains are flagged as suspicious by email providers. Warm up for at least 2 weeks before sending.' },
140 DOMAIN_AGE_UNDER_30: { code: 'DOMAIN_AGE_UNDER_30', severity: 'warning', module: 'whois', message: 'Domain is less than 30 days old.', impact: 'Very young domains have lower sender reputation. Allow 2–4 weeks of warmup before cold outreach.' },
141 DOMAIN_AGE_UNDER_90: { code: 'DOMAIN_AGE_UNDER_90', severity: 'warning', module: 'whois', message: 'Domain is less than 90 days old.', impact: 'Domains under 90 days old may have reduced deliverability. Gradual volume ramp-up is recommended.' },
142
143
144 SSL_SELF_SIGNED: { code: 'SSL_SELF_SIGNED', severity: 'info', module: 'ssl', message: 'SSL certificate is self-signed (not issued by a trusted CA).', impact: 'Self-signed certificates trigger browser warnings but do encrypt traffic.' },
145 SSL_EXPIRING_SOON: { code: 'SSL_EXPIRING_SOON', severity: 'info', module: 'ssl', message: 'SSL certificate expires within 30 days.', impact: 'Renew soon to avoid service disruption and security warnings.' },
146
147
148 SHORT_REGISTRATION: { code: 'SHORT_REGISTRATION', severity: 'info', module: 'whois', message: 'Domain registration length is 1 year or less.', impact: 'Longer registration periods (2+ years) are a minor positive trust signal for email reputation.' },
149 WHOIS_LOOKUP_FAILED: { code: 'WHOIS_LOOKUP_FAILED', severity: 'info', module: 'whois', diagnostic: true, message: 'WHOIS lookup failed or returned no data.', impact: 'Domain age and registration details could not be determined. Some TLDs restrict WHOIS access.' },
150
151
152 DMARC_UPGRADE_AVAILABLE: { code: 'DMARC_UPGRADE_AVAILABLE', severity: 'info', module: 'dmarc', message: "DMARC policy is 'quarantine'. Consider upgrading to 'reject' for maximum protection.", impact: "p=reject tells receiving servers to outright reject unauthenticated email from your domain." },
153 DKIM_MULTIPLE_SELECTORS: { code: 'DKIM_MULTIPLE_SELECTORS', severity: 'info', module: 'dkim', message: 'Multiple DKIM selectors found. Good — this provides redundancy.', impact: 'Multiple valid selectors indicate proper key rotation or multi-provider setup.' },
154
155
156 BLACKLISTED_TIER1: { code: 'BLACKLISTED_TIER1', severity: 'warning', module: 'blacklists', message: 'Listed on a major blacklist. Request delisting.', impact: 'Major blacklists are checked by many mail servers. Listing reduces deliverability significantly.' },
157
158
159 BLACKLISTED_TIER2: { code: 'BLACKLISTED_TIER2', severity: 'info', module: 'blacklists', message: 'Listed on a minor blacklist.', impact: 'Minor blacklists have limited adoption. Listing may slightly affect deliverability with some providers.' },
160 BLACKLIST_CHECK_PARTIAL: { code: 'BLACKLIST_CHECK_PARTIAL', severity: 'info', module: 'blacklists', diagnostic: true, message: 'Some blacklist queries failed (resolver restrictions).', impact: 'Not all blacklists could be checked. Results may be incomplete.' },
161 BLACKLIST_CHECK_FAILED: { code: 'BLACKLIST_CHECK_FAILED', severity: 'warning', module: 'blacklists', diagnostic: true, message: 'All blacklist queries failed. Blacklist status could not be verified.', impact: 'The DNS resolver cannot reach any blacklist zones. Blacklist score is unreliable.' },
162
163
164 IS_CATCH_ALL: { code: 'IS_CATCH_ALL', severity: 'info', module: 'catchAll', message: 'Domain accepts all email addresses (catch-all). ~27% bounce rate risk.', impact: 'Catch-all domains accept mail to any address, making it impossible to verify individual recipients. Lists targeting catch-all domains typically see higher bounce rates.' },
165 CATCH_ALL_CHECK_FAILED: { code: 'CATCH_ALL_CHECK_FAILED', severity: 'info', module: 'catchAll', message: 'Catch-all detection unavailable (port 25 blocked).', impact: 'SMTP probing could not be performed. Catch-all status is unknown.' },
166
167
168 NO_REVERSE_DNS: { code: 'NO_REVERSE_DNS', severity: 'warning', module: 'reverseDns', message: 'MX server IPs have no PTR (reverse DNS) records.', impact: 'Missing reverse DNS is a spam signal. Many receiving servers check that the sending IP has a valid PTR record.' },
169 REVERSE_DNS_MISMATCH: { code: 'REVERSE_DNS_MISMATCH', severity: 'warning', module: 'reverseDns', message: 'PTR hostname does not resolve back to the MX server IP (FCrDNS failure).', impact: 'Forward-confirmed reverse DNS is expected by major email providers. Mismatched PTR records reduce deliverability.' },
170
171
172 DISPOSABLE_DOMAIN: { code: 'DISPOSABLE_DOMAIN', severity: 'critical', module: 'disposable', message: 'Domain is a known disposable/temporary email provider.', impact: 'Disposable domains are used for throwaway signups. Emails sent here are never read and addresses expire quickly.' },
173
174
175 DOMAIN_NXDOMAIN: { code: 'DOMAIN_NXDOMAIN', severity: 'critical', module: 'domainResolves', message: 'Domain does not resolve (NXDOMAIN). No A or AAAA records found.', impact: 'The domain does not exist in DNS. No website, no email, no services. Do not include in outreach.' },
176
177
178 SPF_CHARS_AFTER_ALL: { code: 'SPF_CHARS_AFTER_ALL', severity: 'warning', module: 'spf', message: 'SPF record has content after the "all" mechanism — everything after "all" is ignored.', impact: 'Content after "all" is silently dropped by receivers. This is likely a misconfiguration.' },
179 SPF_VOID_LOOKUPS: { code: 'SPF_VOID_LOOKUPS', severity: 'warning', module: 'spf', message: 'SPF record has more than 2 void DNS lookups (RFC 7208 §4.6.4).', impact: 'Exceeding the void lookup limit may cause PermError on strict receivers.' },
180
181
182 SPF_DUPLICATE_INCLUDE: { code: 'SPF_DUPLICATE_INCLUDE', severity: 'info', module: 'spf', message: 'SPF record contains duplicate include: mechanisms.', impact: 'Duplicate includes waste DNS lookup budget without adding authorization.' },
183
184
185 DMARC_PARTIAL_PCT: { code: 'DMARC_PARTIAL_PCT', severity: 'info', module: 'dmarc', message: 'DMARC pct tag is below 100% — only partial enforcement applied.', impact: 'Not all messages are subject to the DMARC policy. Increase to 100% for full coverage.' },
186 DMARC_EXTERNAL_RUA: { code: 'DMARC_EXTERNAL_RUA', severity: 'info', module: 'dmarc', message: 'DMARC aggregate reporting (rua) points to a different domain.', impact: 'The receiving domain must publish an authorization record or reports will be silently dropped.' },
187 DMARC_EXTERNAL_RUA_UNAUTHORIZED: { code: 'DMARC_EXTERNAL_RUA_UNAUTHORIZED', severity: 'warning', module: 'dmarc', message: 'External DMARC rua domain has no authorization record. Reports will be silently dropped.', impact: 'The rua domain must publish a TXT record at {your-domain}._report._dmarc.{rua-domain} to authorize cross-domain reporting.' },
188
189
190 MX_NO_FALLBACK: { code: 'MX_NO_FALLBACK', severity: 'info', module: 'mx', message: 'Only one MX record — no mail server redundancy.', impact: 'If the single mail server goes down, no backup server can accept email.' },
191
192
193 SSL_EXPIRING_7_DAYS: { code: 'SSL_EXPIRING_7_DAYS', severity: 'warning', module: 'ssl', message: 'SSL certificate expires within 7 days.', impact: 'Imminent expiry — renew immediately to prevent service disruption.' },
194
195
196 MTA_STS_EXPIRED_CERT: { code: 'MTA_STS_EXPIRED_CERT', severity: 'warning', module: 'mtaSts', message: 'MTA-STS policy endpoint has an expired SSL certificate.', impact: 'Sending servers may refuse to fetch the MTA-STS policy, falling back to opportunistic TLS.' },
197 MTA_STS_MX_MISMATCH: { code: 'MTA_STS_MX_MISMATCH', severity: 'warning', module: 'mtaSts', message: 'MTA-STS policy MX entries do not match actual MX records.', impact: 'Sending servers may reject delivery if MX records do not match the MTA-STS policy.' },
198 MTA_STS_MULTIPLE_RECORDS: { code: 'MTA_STS_MULTIPLE_RECORDS', severity: 'warning', module: 'mtaSts', message: 'Multiple _mta-sts TXT records found (must be exactly one).', impact: 'RFC 8461 requires exactly one MTA-STS TXT record. Multiple records may cause policy lookup failure.' },
199 MTA_STS_INVALID_POLICY: { code: 'MTA_STS_INVALID_POLICY', severity: 'warning', module: 'mtaSts', message: 'MTA-STS policy file is missing required fields (version, mode, mx, or max_age).', impact: 'An incomplete policy may be ignored by sending servers, falling back to opportunistic TLS.' },
200
201
202 BIMI_NO_VMC: { code: 'BIMI_NO_VMC', severity: 'info', module: 'bimi', message: 'BIMI record found but no VMC (Verified Mark Certificate).', impact: 'Without a VMC, the brand logo will not display in Gmail. Other providers may still show it.' },
203 BIMI_REQUIRES_DMARC_ENFORCEMENT: { code: 'BIMI_REQUIRES_DMARC_ENFORCEMENT', severity: 'warning', module: 'bimi', message: 'BIMI detected but DMARC policy is "none" — BIMI requires "quarantine" or "reject".', impact: 'BIMI logos are only displayed when the domain has a strong DMARC policy. Upgrade from p=none.' },
204
205
206 HAS_BIMI: { code: 'HAS_BIMI', severity: 'info', module: 'bimi', message: 'Domain has a BIMI record — brand logo appears in supported inboxes.', impact: 'BIMI (Brand Indicators for Message Identification) displays a verified logo next to emails. Indicates advanced email authentication maturity.' },
207 BIMI_VMC_VALID: { code: 'BIMI_VMC_VALID', severity: 'info', module: 'bimi', message: 'VMC (Verified Mark Certificate) is valid and issued by a recognized CA.', impact: 'A valid VMC from DigiCert or Entrust ensures the brand logo displays in Gmail and other supporting clients.' },
208
209
210 BIMI_VMC_EXPIRED: { code: 'BIMI_VMC_EXPIRED', severity: 'warning', module: 'bimi', message: 'VMC (Verified Mark Certificate) has expired.', impact: 'An expired VMC prevents the brand logo from displaying. Renew the certificate.' },
211 BIMI_VMC_INVALID_ISSUER: { code: 'BIMI_VMC_INVALID_ISSUER', severity: 'info', module: 'bimi', message: 'VMC issuer is not a recognized BIMI certificate authority (DigiCert or Entrust).', impact: 'Only VMCs issued by DigiCert or Entrust are accepted by Gmail. Other issuers may work with some providers.' },
212
213
214 BIMI_VMC_FETCH_FAILED: { code: 'BIMI_VMC_FETCH_FAILED', severity: 'info', module: 'bimi', diagnostic: true, message: 'Could not fetch the VMC certificate from the authority URL.', impact: 'The VMC URL may be unreachable or returning errors. Brand logo display requires an accessible certificate.' },
215
216
217 TLSRPT_PUBLISHED: { code: 'TLSRPT_PUBLISHED', severity: 'info', module: 'tlsrpt', message: 'TLS reporting (TLSRPT) is configured — TLS delivery failures are being monitored.', impact: 'TLSRPT enables receiving domains to report TLS connection failures back to senders.' },
218 NO_TLSRPT: { code: 'NO_TLSRPT', severity: 'info', module: 'tlsrpt', message: 'No TLSRPT record found. TLS delivery failure reporting is not configured.', impact: 'Without TLSRPT, you cannot monitor whether sending servers fail to establish TLS connections.' },
219
220
221 TLSRPT_INVALID_SYNTAX: { code: 'TLSRPT_INVALID_SYNTAX', severity: 'warning', module: 'tlsrpt', message: 'TLSRPT record found but has syntax errors.', impact: 'Sending servers may not be able to parse the TLSRPT record, preventing failure reporting.' },
222 TLSRPT_MULTIPLE_RECORDS: { code: 'TLSRPT_MULTIPLE_RECORDS', severity: 'warning', module: 'tlsrpt', message: 'Multiple TLSRPT TXT records found (must be exactly one).', impact: 'RFC 8460 requires exactly one TLSRPT record. Multiple records may cause lookup failure.' },
223
224
225 NO_MTA_STS: { code: 'NO_MTA_STS', severity: 'info', module: 'mtaSts', message: 'No MTA-STS record found. Inbound mail transport is not enforcing TLS.', impact: 'Without MTA-STS, mail servers connecting to this domain may fall back to unencrypted delivery.' },
226 MTA_STS_TESTING: { code: 'MTA_STS_TESTING', severity: 'info', module: 'mtaSts', message: 'MTA-STS policy is in testing mode. TLS failures are reported but not enforced.', impact: 'Testing mode helps identify connectivity issues before enforcing TLS. Upgrade to enforce when ready.' },
227 MTA_STS_ENFORCED: { code: 'MTA_STS_ENFORCED', severity: 'info', module: 'mtaSts', message: 'MTA-STS policy enforces TLS for inbound mail. Excellent security posture.', impact: 'All sending servers must use TLS when delivering to this domain. Unencrypted connections are rejected.' },
228 MTA_STS_POLICY_FETCH_FAILED: { code: 'MTA_STS_POLICY_FETCH_FAILED', severity: 'info', module: 'mtaSts', diagnostic: true, message: 'MTA-STS DNS record found but HTTPS policy file could not be fetched.', impact: 'The policy file at https://mta-sts.{domain}/.well-known/mta-sts.txt is missing or unreachable.' },
229
230
231 DOMAIN_NO_WEB_PRESENCE: { code: 'DOMAIN_NO_WEB_PRESENCE', severity: 'info', module: 'website', message: 'No website found at this domain.', impact: 'Domains used for cold email typically redirect to a main website. No web presence may look suspicious to recipients.' },
232};