UNPKG

email-domain-check

Version:

Comprehensive email domain validation library with DNS, MX, SMTP, DKIM, DMARC and MTA-STS support.

131 lines (130 loc) 4.68 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Address = exports.IPKind = void 0; const node_net_1 = __importDefault(require("node:net")); const node_url_1 = require("node:url"); var IPKind; (function (IPKind) { IPKind[IPKind["None"] = 0] = "None"; IPKind[IPKind["IPv4"] = 4] = "IPv4"; IPKind[IPKind["IPv6"] = 6] = "IPv6"; })(IPKind || (exports.IPKind = IPKind = {})); class Address { source; ipKind; user; hostname; constructor(mailOrHost) { this.source = mailOrHost; const atPos = mailOrHost.indexOf('@'); if (atPos >= 0) { //email literal this.user = mailOrHost.slice(0, atPos); const domainPart = mailOrHost.slice(atPos + 1); this.ipKind = node_net_1.default.isIP(domainPart); if (this.ipKind !== IPKind.None) { this.hostname = domainPart; } else { // RFC 5321 / RFC 5322 // Check if the domain looks like an IP literal. IP addresses need to be enclosed in square brackets // user@[127.0.0.1] // user@[IPv6:2001:db8:1ff::a0b:dbd0] if (/^\[(ipv6:)?[^\]]+\]$/i.test(domainPart)) { const cleanDomain = domainPart.replace(/^\[(ipv6:)?|\]$/gi, ''); this.ipKind = node_net_1.default.isIP(cleanDomain); if (this.ipKind !== IPKind.None) { this.hostname = cleanDomain; } else { throw new Error(`Parse error source:${domainPart}`); } } else { const noDot = domainPart.replace(/\.$/, ''); this.hostname = (0, node_url_1.domainToASCII)(noDot).toLowerCase(); } } } else { // hostname literal this.ipKind = node_net_1.default.isIP(mailOrHost); if (this.ipKind !== IPKind.None) { this.hostname = mailOrHost; } else { const noDot = mailOrHost.replace(/\.$/, ''); this.hostname = (0, node_url_1.domainToASCII)(noDot).toLowerCase(); } } } static loadFromTarget(target) { if (target instanceof Address) { return target; } else if (target instanceof URL) { return new Address(target.hostname); } else { return new Address(target); } } get isIP() { return this.ipKind !== IPKind.None; } get hasPunycode() { if (this.hostname) { return this.hostname.split('.').some((part) => part.startsWith('xn--')); } return false; } // Special IPv4 address ranges. // See also https://en.wikipedia.org/wiki/Reserved_IP_addresses get isLocal() { if (this.ipKind === IPKind.IPv4) { const parts = this.hostname.split('.').map(Number); // Loopback: 127.0.0.0/8 if (parts[0] === 127) return true; // Private: 10.0.0.0/8 if (parts[0] === 10) return true; // Private: 172.16.0.0/12 (172.16.0.0 - 172.31.255.255) if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true; // Private: 192.168.0.0/16 if (parts[0] === 192 && parts[1] === 168) return true; // Unspecified/This network: 0.0.0.0/8 if (parts[0] === 0) return true; // Link-local: 169.254.0.0/16 if (parts[0] === 169 && parts[1] === 254) return true; } else if (this.ipKind === IPKind.IPv6) { const lower = this.hostname.toLowerCase(); // Loopback: ::1 if (lower === '::1' || lower === '0:0:0:0:0:0:0:1') return true; // Link-local: fe80::/10 if (lower.startsWith('fe80:')) return true; // Unique local: fc00::/7 if (lower.startsWith('fc') || lower.startsWith('fd')) return true; // Unspecified: :: if (lower === '::') return true; } else { if (this.hostname === 'localhost') return true; } return false; } } exports.Address = Address;