UNPKG

3.6 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.verifyMailboxSMTP = void 0;
7const net_1 = __importDefault(require("net"));
8/**
9 * @param {String} smtpReply A message from the SMTP server.
10 * @return {Boolean} True if over quota.
11 */
12function isOverQuota(smtpReply) {
13 return smtpReply && /(over quota)/gi.test(smtpReply);
14}
15/**
16 * @see https://support.google.com/a/answer/3221692?hl=en
17 * @see http://www.greenend.org.uk/rjk/tech/smtpreplies.html
18 * @param {String} smtpReply A response from the SMTP server.
19 * @return {boolean} True if the error is recognized as a mailbox missing error.
20 */
21function isInvalidMailboxError(smtpReply) {
22 return smtpReply && /^(510|511|513|550|551|553)/.test(smtpReply) && !/(junk|spam|openspf|spoofing|host|rbl.+blocked)/gi.test(smtpReply);
23}
24/**
25 * @see https://www.ietf.org/mail-archive/web/ietf-smtp/current/msg06344.html
26 * @param {String} smtpReply A message from the SMTP server.
27 * @return {Boolean} True if this is a multiline greet.
28 */
29function isMultilineGreet(smtpReply) {
30 return smtpReply && /^(250|220)-/.test(smtpReply);
31}
32const logMethod = console.debug;
33async function verifyMailboxSMTP(params) {
34 // Port 587 → STARTTLS
35 // Port 465 → TLS
36 const { local, domain, mxRecords = [], timeout, debug, port = 25 } = params;
37 const mxRecord = mxRecords[0];
38 const log = debug ? logMethod : () => { };
39 if (!mxRecord) {
40 return false;
41 }
42 return new Promise((resolve) => {
43 const socket = net_1.default.connect(port, mxRecord);
44 // eslint-disable-next-line prefer-const
45 let resTimeout;
46 let resolved;
47 const ret = (result) => {
48 if (resolved)
49 return;
50 if (!(socket === null || socket === void 0 ? void 0 : socket.destroyed)) {
51 socket === null || socket === void 0 ? void 0 : socket.write('QUIT\r\n');
52 socket === null || socket === void 0 ? void 0 : socket.end();
53 }
54 clearTimeout(resTimeout);
55 resolve(result);
56 resolved = true;
57 };
58 const messages = [`HELO ${domain}`, `MAIL FROM: <${local}@${domain}>`, `RCPT TO: <${local}@${domain}>`];
59 socket.on('data', (data) => {
60 log('Mailbox: got data', data);
61 if (isInvalidMailboxError(data))
62 return ret(false);
63 if (isOverQuota(data))
64 return ret(false);
65 if (!data.includes('220') && !data.includes('250'))
66 return ret(null);
67 if (isMultilineGreet(data))
68 return;
69 if (messages.length > 0) {
70 const message = messages.shift();
71 log('Mailbox: writing message', message);
72 return socket.write(message + '\r\n');
73 }
74 ret(true);
75 });
76 socket.on('error', (err) => {
77 log('Mailbox: error in socket', err);
78 ret(null);
79 });
80 socket.on('close', (err) => {
81 log('Mailbox: close socket', err);
82 ret(null);
83 });
84 socket.on('timeout', () => {
85 log('Mailbox: timeout socket');
86 ret(null);
87 });
88 resTimeout = setTimeout(() => {
89 log(`Mailbox: timed out (${timeout} ms)`);
90 socket.destroy();
91 ret(null);
92 }, timeout);
93 });
94}
95exports.verifyMailboxSMTP = verifyMailboxSMTP;