如何使用 Express、Node 和 Gmail 构建 SMTP 邮件服务器

2025-05-25

如何使用 Express、Node 和 Gmail 构建 SMTP 邮件服务器

概述

最近,我有机会开发一个 SMTP 电子邮件服务器,并将其集成到一个更复杂的全栈应用程序中。今天,我们将在本教程中引用我的解决方案中的代码。

我们将主要使用 Express 和 Node 来创建此服务器。我们还将集成 Nodemailer 来构建可邮寄对象,并使用 Gmail SMTP 服务器来免费发送电子邮件。

完整的代码库可以在这里查看:


GitHub 徽标 killshot13 / express-smtp-mailer

一个可用于生产的 Node 后端,带有可配置的 Express SMTP 邮件服务器,可用于联系表单、订阅等。


特征

在开始编码之前,我们应该量化 Express 邮件服务器的预期功能。如果出现疑问,可以随时参考此列表。

  1. 建立到前端联系表单的API 路由。

  2. 提交表单后从这些路线接收用户数据。

  3. 使用收到的数据格式化可邮寄的 JSON 对象。

  4. 使用 Nodemailer构建传输功能,为投递做准备。

  5. 使用存储在服务器中的凭据从 Gmail获取授权。

  6. 调用传输函数,提示 Nodemailer 将电子邮件对象交给 Gmail SMTP 服务器进行传递。

  7. 请求确认传送成功,如果未收到则返回错误消息。

完成后,我们将拥有一个完美的后端来处理联系表单。此外,我们的服务器还将为构建功能丰富的全栈 MERN 应用提供坚实的基础。

我们今天正在构建的服务器的生产版本为南佛罗里达州的房地产投资公司Ormica的后端提供支持。


GitHub 上的源代码截图


先决条件

  • 对基本编程概念有基本的了解,并熟悉至少一种服务器端编程语言,例如 [ NodePythonRubyPHP]。

  • 代码编辑器(例如Visual Studio)

  • 本地安装Node.jsnpm。(建议使用当前 LTS 版本)

包括我在内的一些开发人员更喜欢使用nvmnvm-windows来简化 Node 版本管理,这完全没问题。

如需进一步参考,您还可以查看如何在 MacOS 上使用 NVM 的多个 Node 版本 - Node 版本管理器


发展

第 1 部分 依赖项

时机已到!该写点代码了。

从这些终端命令开始,在您希望存储服务器本地版本的任何位置创建一个空目录,并使用 npm 创建第一个文件。


    mkdir smtp-email-server
    cd smtp-email-server
    npm init
Enter fullscreen mode Exit fullscreen mode

按照 npm 终端的提示创建一个 package.json 文件。大多数情况下,默认值即可,但请务必将入口点更改为 ,server.js而不是建议的index.js

现在我们需要将所需的依赖项(npm 包)添加到项目中。运行以下命令,您会注意到 npm 会自动创建一个名为 的新目录node_modules。这是正常现象,因此请勿更改或配置此文件夹中的任何内容。


    npm install express nodemailer morgan dotenv
Enter fullscreen mode Exit fullscreen mode

让我们看一下每个包的简要概述。

  • Express是一个简约而灵活的 Node.js Web 应用程序框架,提供了一组强大的功能。

  • Nodemailer是一个旨在允许 Node.js 应用程序安全高效地发送电子邮件的模块。

  • Morgan以 Dexter(一部你不应该看完的电视剧)命名,并为 Node.js 提供 HTTP 请求记录器中间件。

  • dotenv是一个零依赖模块,它将环境变量从.env文件加载到process.env.


第 2 部分 路线

让我们首先创建一个routes包含的文件夹routes.js


    mkdir routes && cd routes && touch routes.js
Enter fullscreen mode Exit fullscreen mode

在代码编辑器中打开routes.js并通过要求文件顶部的依赖项来建立基线。


    require("dotenv").config();
    // routes.js
    const router = require("express").Router();
    const path = require("path");
    const nodemailer = require("nodemailer");
Enter fullscreen mode Exit fullscreen mode

如你所见,Express 有它自己的内置路由器。我选择使用这个选项,而不是使用单独的 npm 包。这有助于保持我们的应用程序轻量且高效。

我们的下一步工作是使用 Gmail 帐户凭据设置身份验证。别忘了将.env文件添加到根目录,而不是当前位置。


    const transport = {
        //this is the authentication for sending email.
        host: "smtp.gmail.com",
        port: 465,
        secure: true, // use TLS
        /* create a .env file and define your credentials. */
        auth: {
            user: process.env.SMTP_TO_EMAIL,
            pass: process.env.SMTP_TO_PASSWORD,
        },
     };
Enter fullscreen mode Exit fullscreen mode

还记得我们之前提到的传输函数吗?在这一步中,我们将构建相同的函数。我们来看看吧!


    // call the transport function
    const transporter = nodemailer.createTransport(transport);
    transporter.verify((error, success) => {
        if (error) {
            //if error happened code ends here
            console.error(error);
         } else {
            //this means success
            console.log("Ready to send mail!");
         }
    })
Enter fullscreen mode Exit fullscreen mode

现在让我们构建 API 路由。同时,我们将定义 JSON 对象(电子邮件)的架构。

简单来说,我们告诉 Nodemailer 它将从前端接收的表单数据以及如何将所述数据转换为结构化电子邮件。

最后,我们调用该transporter.sendMail函数,Nodemailer 发挥它的魔力,电子邮件顺利进入收件人的收件箱。


    router.get('/', (req, res, next) => {
        res.status(200).json({ msg: 'Working' })
    })
    router.post('/', (req, res, next) => {
        //make mailable object
        const mail = {
        from: process.env.SMTP_FROM_EMAIL,
        to: process.env.SMTP_TO_EMAIL,
        subject: 'New Contact Form Submission',
        text: `Contact Details:
                   Name: ${req.body.name} 
                   Email: ${req.body.email} 
                   Phone: ${req.body.tel} 
                   Message: ${req.body.message}` 
         }
         transporter.sendMail(mail, (err, data) => {
        if (err) {
            res.json({
                status: 'fail',
            })
            } else {
            res.json({
                status: 'success',
            })
        }
        })
    })
Enter fullscreen mode Exit fullscreen mode

该文件中的最后一段代码指示 Express 使用我们建立的路由;最后,我们将整个路由器导出到 Node 服务器。


    // Answer API requests.
    router.use('/api', function (req, res) {
        res.set('Content-Type', 'application/json')
        res.send('{"message":"Hello from the custom server!"}')
    })
    /* All remaining requests return the React app, so it can 
    handle routing. */
    router.use('*', function (request, response) { 
        response.sendFile(path.resolve(__dirname, '/react- 
        ui/build', 'index.html'))
    })
    module.exports = router
Enter fullscreen mode Exit fullscreen mode

注意:如果您不熟悉process.env或者仅仅需要复习一下,这篇 Codeburst 文章提供了一个很好的参考点。


第 3 部分服务器

我们server.js在根目录中创建一个文件并用编辑器打开它。

这里我们只是确保一切顺利进行。我可以就这里定义的每个参数写一整篇文章,但这个模板已经相当标准了。

让我们首先定义一些初始要求。


    const express = require('express')
    const cluster = require('cluster')
    const numCPUs = require('os').cpus().length
Enter fullscreen mode Exit fullscreen mode

现在我们应该检查环境,看看是否在生产环境中运行。如果是,我们会使用Node 进程集群,尽可能均匀地将应用程序运行的压力分散到各个服务器核心上。


    const isDev = process.env.NODE_ENV !== 'production'
    /* Multi-process to utilize all CPU cores. */
    if (!isDev && cluster.isMaster) {
        console.error(`Node cluster master ${process.pid} is running`)
         // Fork workers.
         for (let i = 0; i < numCPUs; i++) { 
             cluster.fork() 
         } 
    cluster.on('exit', (worker, code, signal) => {
        console.error(`Node cluster worker ${worker.process.pid} 
    exited: code ${code}, signal ${signal}`)
        })
    }
Enter fullscreen mode Exit fullscreen mode

然后,我们将连接到前端,优先提供我们的静态 HTML 文件,定义一些用于 AJAX 解析的中间件,最后调用我们从文件导入的路由routes.js,所有这些都按顺序进行。

我们为开发环境添加了一些错误日志记录,瞧!我们的 Express 邮件服务器运行正常。


     else {
    const app = express()
    const limiter = new rateLimit({
        windowMs: 1 * 60 * 1000, // 1 minute
        max: 5,
    })
    const morgan = require('morgan')
    const path = require('path')

    const PORT = process.env.PORT || 5000

    // apply rate limiter to all requests
    app.use(limiter)

    // Priority serve any static files.
    // Replace the example to connect to your frontend.
    app.use(express.static(path.join(__dirname, 
        '/example/frontend.js')))

    // dev middleware
    app.use(morgan('dev'))

    // configure body parser for AJAX requests
    app.use(express.urlencoded({ extended: false }))
    app.use(express.json())

    const routes = require('./routes/routes')

    // after all middleware functions
    app.use('/', routes)

        app.listen(PORT, function () {
        console.error(
            `Node ${
                isDev ? 'dev server' : 'cluster 
         worker ' + process.pid
            }: listening on port ${PORT}`
        )
    })
    }
Enter fullscreen mode Exit fullscreen mode

SMTP 邮件服务器已完成!恭喜!

注意:如果您在身份验证过程中遇到困难,请阅读此 Google 支持文档!它将为您节省数小时的调试和 Excedrin 时间。



结论

我们已成功使用 Express 和 Node 创建了 SMTP 电子邮件服务器。我们还学习了如何集成 Nodemailer 和 Gmail 来简化邮件发送流程。


GitHub 徽标 killshot13 / express-smtp-mailer

一个可用于生产的 Node 后端,带有可配置的 Express SMTP 邮件服务器,可用于联系表单、订阅等。


欢迎随意克隆源代码并探索您自己的实现方法。希望您觉得本教程有用,并感谢您花时间学习!

别忘了💖这篇文章并留下💭。如果你觉得特别慷慨,请点击下方我的名字来🎆订阅🎇!

-- killshot13


killshot13 图片

文章来源:https://dev.to/killshot13/how-to-build-an-smtp-mail-server-with-express-node-and-gmail-aof
PREV
我使用 TypeScript 编写了一个功能齐全的文件资源管理器。
NEXT
使用 React、Typescript、Node 和 Socket.io 制作的即时通讯应用程序 🦜 目录 项目介绍 👋 功能 🌟 技术栈 ⚛️ 线框和设计 🎨 数据建模和 API 路由 💾 项目组织 🗂️ Sprint 01:设置和前端 🖥 Sprint 02:后端 📊 Sprint 03:修复和部署 ☁️ 结论✅