使用节点js验证电子邮件(检查电子邮件收件箱是否存在)

问题描述 投票:0回答:1

我正在寻找一种使用 Node js 以编程方式检查电子邮件是否为有效电子邮件的方法。经过一些研究后,我最终找到了这个 YouTube 视频

现在看完视频后,我有了这个代码:

const { randomBytes } = require('crypto');
const promises = require('dns').promises;
const net = require('net');


const resolveMXRecords = async (domain) => {
    console.log('resolving mx records for domain...', domain)
    try {
        return await promises.resolveMx(domain)
    } catch (error) {
        return []
    }
}

const verifyEmailFormat = (email) => {
    const regex = new RegExp({ pattern: '^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,4}$', flags: 'i' });
    return regex.test(email);
};

const SMTPStages = {
    CHECK_CONNECTION_ESTABLISHED: 'CHECK_CONNECTION_ESTABLISHED',
    SEND_EHLO: 'SEND_EHLO',
    SEND_MAIL_FROM: 'SEND_MAIL_FROM',
    SEND_RECIPIENT_TO: 'SEND_RECIPIENT_TO',
    SEND_QUIT: 'SEND_QUIT'
}

const testInboxOnSMTPServer = async (inboxAddress, smtpAddress) => {
    return new Promise((resolve, reject) => {
        const result = {
            connection_established: false,
            account_exists: false
        }

        const socket = net.createConnection(25, smtpAddress)
        const stages = {
            [SMTPStages.CHECK_CONNECTION_ESTABLISHED]: {
                expected_reply_code: '220'
            },
            [SMTPStages.SEND_EHLO]: {
                command: `EHLO mail.example.org\r\n`,
                expected_reply_code: '250'
            },
            [SMTPStages.SEND_MAIL_FROM]: {
                command: `MAIL FROM:<[email protected]>\r\n`,
                expected_reply_code: '250'
            },
            [SMTPStages.SEND_RECIPIENT_TO]: {
                command: `RCPT TO:<${inboxAddress}>\r\n`,
                expected_reply_code: '250'
            },
            [SMTPStages.SEND_QUIT]: {
                command: `QUIT\r\n`,
                expected_reply_code: '221'
            }
        }

        let response = ""
        let currentStageName = SMTPStages.CHECK_CONNECTION_ESTABLISHED

        socket.on("data", (data) => {
            const reply = data.toString()
            response += reply

            // console.log('<-- ' + reply)
            const currentStage = stages[currentStageName]

            switch (currentStageName) {
                case SMTPStages.CHECK_CONNECTION_ESTABLISHED: {
                    if (!reply.startsWith(currentStage.expected_reply_code)) {
                        socket.end()
                        break
                    }

                    result.connection_established = true
                    currentStageName = SMTPStages.SEND_EHLO
                    const command = stages[currentStageName].command
                    socket.write(command, () => {
                        console.log('--> ' + command)
                    })

                    break
                }

                case SMTPStages.SEND_EHLO: {
                    if (!reply.startsWith(currentStage.expected_reply_code)) {
                        socket.end()
                        break
                    }

                    currentStageName = SMTPStages.SEND_MAIL_FROM
                    const command = stages[currentStageName].command
                    socket.write(command, () => {
                        console.log('--> ' + command)
                    })

                    break
                }

                case SMTPStages.SEND_MAIL_FROM: {
                    if (!reply.startsWith(currentStage.expected_reply_code)) {
                        socket.end()
                        break
                    }

                    currentStageName = SMTPStages.SEND_RECIPIENT_TO
                    const command = stages[currentStageName].command
                    socket.write(command, () => {
                        console.log('--> ' + command)
                    })

                    break
                }

                case SMTPStages.SEND_RECIPIENT_TO: {
                    if (!reply.startsWith(currentStage.expected_reply_code)) {
                        socket.end()
                        break
                    }

                    result.account_exists = true
                    currentStageName = SMTPStages.SEND_QUIT
                    const command = stages[currentStageName].command
                    socket.write(command, () => {
                        console.log('--> ' + command)
                    })

                    break
                }
            }
        })

        socket.on("connect", () => {
            console.log("Connected to SMTP " + smtpAddress)
            console.log('Local address: ' + socket.localAddress + ' Local port: ' + socket.localPort);
            console.log('Remote address: ' + socket.remoteAddress + ' Remote port: ' + socket.remotePort);
        })

        socket.on("error", (error) => {
            // clearInterval(timeoutTimer)
            reject(error)
        })

        socket.on("close", () => {
            // clearInterval(timeoutTimer)
            resolve(result)
        })
    })
}

const validateEmail = async (email) => {
    const emailFormatValid = verifyEmailFormat(email)
    if (!emailFormatValid) {
        return 'invalid email format'
    }

    const [, domain] = email.split('@')
    const mxRecords = await resolveMXRecords(domain)
    const sortedMxRecords = mxRecords.sort((a, b) => a.priority - b.priority)
    console.log('sortedMxRecords', sortedMxRecords)

    let smtpResult = { connection_established: false, account_exists: false }
    let hostIndex = 0

    while (hostIndex < sortedMxRecords.length) {
        try {
            console.log('testing inbox on smtp server', sortedMxRecords[hostIndex].exchange)
            smtpResult = await testInboxOnSMTPServer(email, sortedMxRecords[hostIndex].exchange)
            if (!smtpResult.connection_established) {
                console.log('connection not established')
                hostIndex++
            }
            else {
                break
            }
        } catch (error) {
            console.error('error while testing inbox on smtp server', error)
            hostIndex++
        }
    }
    let usesCatchAll = false
    try {
        const testCatchEmail = `${randomBytes(20).toString('hex')}@${domain}`
        const testCatchAll = await testInboxOnSMTPServer(testCatchEmail, sortedMxRecords[hostIndex].exchange)
        usesCatchAll = testCatchAll.account_exists
    } catch (error) {
        console.error(error)
    }

    return {
        email_format_is_valid: emailFormatValid,
        usesCatchAll: usesCatchAll,
        ...smtpResult
    }

}

async function main() {
    let email = '[email protected]'
    const result = await validateEmail(email)
    console.log('result', result)
}
main()

此代码在大多数情况下都有效。当我尝试运行它时,它给出了一些准确的结果。但我面临一些问题,第一个是当我尝试在远程 Linux 服务器上运行相同的代码时,它不断地给我一个连接错误。其次,我想检查一个非常大的电子邮件列表(大约 400 万封)。如何实现这一目标而不被服务器阻止或禁止?如何处理某些电子邮件的连接问题?任何帮助将不胜感激。

javascript node.js email automation smtp
1个回答
0
投票

让我们看看另一个变体来做到这一点,我认为它更容易。

  1. 首先,您必须使用以下命令安装 Deep Email Validator:
    npm install deep-email-validator
  2. 然后您必须创建执行验证的逻辑。它看起来像这样:
    const router = express.Router();
    const emailValidator = require('deep-email-validator');
    async function isEmailValid(email) {
    return emailValidator.validate(email)
    }
    
    
  3. 当异步函数运行时,您将得到以下响应:
      valid: false,
      validators: {
        regex: { valid: true },
        typo: { valid: true },
        disposable: { valid: true },
        mx: { valid: true },
        smtp: { valid: false, reason: 'Mailbox not found.' }
      },
      reason: 'smtp'
    }
    
    
    
  4. 如您所见,深度电子邮件验证器运行五种不同的检查来确保电子邮件地址的有效性。在这种情况下,ID 无效,因为 SMTP 存在问题。找不到邮箱。这就是为什么 valid 字段设置为 false,reason 字段设置为 smtp。它不应该返回 false。

您可以在此处

阅读有关此验证的更多信息
© www.soinside.com 2019 - 2024. All rights reserved.