本篇文章将介绍如何使用 Docker 快速搭建一个适用于 HomeLab 和开发阶段使用的邮件网关,用来快速聚合各种软件的通知消息。当然,你也可以用它来快速验证各种软件中的邮件配置是否正确。

如果你熟悉 Docker 的话,大概十分钟,你将会拥有一套完全属于自己的邮件通知聚合服务,而这个服务,只需要 20MB 左右的内存消耗,非常轻量。

写在前面

最近在整理家里的部署的软件和服务,这些服务多数都拥有“邮件通知”的能力,并会在必要的时候,使用“发送邮件”的方式通知用户一些必要的信息,比如:任务执行完毕、敏感操作、根据计划任务跑完的数据统计摘要等。

以往部署这些软件的时候,在邮件通知功能配置上,我们的选择无非是三种:注册一个真实的邮箱,使用我们自己已经在用的邮箱账号,关闭邮件通知功能。

当软件比较少的时候,不论选择那种方案,都是可以的,因为我们的一次性操作和维护成本都比较低

但当我们部署了越来越多的软件和服务之后,关闭邮件通知属于“鸵鸟行为”,是不推荐的;在不能100%确定软件可靠性的前提下,所有软件共享一个邮箱账号,显然是不安全的;最可靠的方案,便是为为每一个软件配置不同的邮箱账号

而如果为每一个软件都配置独立的邮箱账号,维护邮箱账号的时间成本,将会变得不可忽视,因为你永远不知道什么时候、哪一个邮箱账号会有问题,以及在什么时候你会漏掉重要的应用消息。

所以,我开始寻找一个适用于个人或者小团队的、私有化部署的邮件网关方案,降低账号的维护成本和经济成本,以及尽可能减少不必要的公网数据交换。

软件选型

为了解决上面的问题,一般可以选择两类软件方案:邮局类软件、邮件测试网关。

我们先来聊聊邮局类应用。

邮局类软件应用

邮局类软件,顾名思义,和我们日常使用的 GMail、Outlook、QQ 邮箱、163 邮箱等等。在 GitHub 上,我们也可以找到不少优秀的邮局软件应用,比如下面这些:

上面的开源方案都可以作为我们日常使用的云服务、知名邮件厂商的替代方案使用。

但是通常情况下,这类软件会包含非常多的组件和能力,比如:Web 界面、多账户支持、多种邮局聚合、各种邮件协议支持、邮件推送、垃圾邮件审查、邮件防火墙、各种复杂的邮件相关的 DNS 支持等等。

随着软件功能的丰富完善,软件运行过程中的资源消耗和使用中的功能复杂度自然也就上去了,加上这几个头部的项目,技术选型多是 Ruby、Python,资源使用自然更是“雪上加霜”。

考虑到我不需要多用户支持,并且我希望我的应用始终是轻量可靠的。所以,我将目光转向了:测试网关类应用。

邮件测试网关类应用

坦白说,能够符合我前文中提到的大部分需求,并具备比较低的资源占用的项目并不多。如果再限制能够快速进行功能验证(跑起来看效果)的项目,那就更屈指可数啦:

在简单使用之后,我选择了以第二个项目,将它作为代码基进行二次开发。毕竟基于在以往项目中的经验,相比较 Ruby 的性能和效率,我对 Node 更有信心。

如果你等不及验证效果,可以跳过下面的小节,直接阅读文章的 “使用 Docker 进行快速体验”部分。

基于 MailDev 进行二次开发

从项目当前出现的问题和社区里的反馈里,我们可以看到几个比较明显的问题:

  1. 软件文档和官方镜像似乎“对不上号”,一些代码中的依赖配置项也是有问题的,会导致软件无法正常使用。 issue #376issue list
  2. 作者官宣弃坑,后来者做了 fork 版本,但仅仅是解决了一些基础问题。issue #335
  3. 软件依赖和运行时都过于陈旧,依赖的 lib 的版本缺乏有效管理,NPM 子依赖中不少依赖都已经被废弃或者存在安全隐患。
  4. 使用更可靠的 Markdown 和 HTML 互相转化方案,对内容进行安全的标签过滤。

所以,我花了一些时间,针对原来的代码做了一些调整:

  • 升级了 Node Runtime 到 v16 TLS。
  • 将各种基础依赖升级到可靠版本,解决各种安全问题。
  • 重新构建可用的 Docker 容器版本。

针对 MailDev 进行细节调整

如果你好奇到底改了哪些内容的话,可以看这里的提交记录:https://github.com/maildev/maildev/compare/master…soulteary:master

接下来,我们来看看如何通过容器快速使用这个“邮件工具”吧。

使用 Docker 快速体验邮件网关

如果我们想启动一个“邮件网关”,可以直接使用“一句话”的容器命令来解决战斗:

docker run -p 1080:1080 -p 1025:1025 soulteary/maildev

当命令执行完毕,我们将能够看到类似下面的日志输出:

MailDev using directory /tmp/maildev-1
MailDev webapp running at http://0.0.0.0:1080
MailDev SMTP Server running at 0.0.0.0:1025

接着在浏览器中打开 http://0.0.0.0:1080,就能看到下图一样的收件箱界面了。

MailDev 的欢迎界面

如果我们需要测试邮件聚合功能是否能够正常工作,只需要使用邮件客户端、配置任意用户名和密码,向 0.0.0.0:1025 端口发送邮件,就能够看到效果啦。

还记得上文中需要配置不同账号的问题吗?是不是很轻松的就解决啦?甚至你还可以配置邮件转发真实邮箱、限制只接收某些账号的邮件消息。

使用 Node.js 快速验证服务功能

相比较使用客户端,我更喜欢使用代码来做快速验证。

这里为了方便描述,我使用 Node.js 写了一个非常简单的发信脚本:

'use strict'

const nodemailer = require('nodemailer')

async function main () {
  const { user, pass } = await nodemailer.createTestAccount()
  let transporter = nodemailer.createTransport({
    host: '0.0.0.0',
    port: 1025,
    auth: { type: 'login', user, pass }
  })

  // send mail with defined transport object
  let info = await transporter.sendMail({
    from: '\'Fred Foo 👻\' <foo@example.com>', // sender address
    to: 'bar@example.com, baz@example.com', // list of receivers
    subject: 'Hello ✔', // Subject line
    text: 'Hello world?', // plain text body
    html: '<b>Hello world?</b>' // html body
  })

  console.log('Message sent: %s', info.messageId)
  // Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>

  // Preview only available when sending through an Ethereal account
  console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info))
  // Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
}

main().catch(console.error)

将上面的代码保存为 example-sendmail.js,接着执行 node example-sendmail.js,顺利的话,我们将看到类似下面的日志输出:

Message sent: <c9867b60-8c5d-df8d-2476-39f5dd77f856@example.com>
Preview URL: false `

接着,在浏览器中打开 http://0.0.0.0:1080,我们将看到 MailDev 的界面中多了一份意料之中的“邮件”,邮件正文正是我们上面写代码中的内容。

收到来信的 MailDev

在不进行额外的代码调整之前,我们多重复几次上面的发信操作,就可以模拟出日常学习和工作中各种应用的邮件通知发送场景。

此时,MailDev 的列表中就会实时展示新到的“邮件”了。

MailDev 的邮件列表

使用 Docker-Compose 启动服务

为了方便我的老读者们,让大家能够一起偷懒,按照惯例,我提供一个简单的容器编排配置文件:

version: '3'

services:

  maildev:
    image: soulteary/maildev
    restart: always
    environment:
      - TZ=Asia/Shanghai
      - MAILDEV_WEB_PORT=1080
      - MAILDEV_SMTP_PORT=1025
    ports:
      - "1080:1080"
      - "1025:1025"

将上面的内容保存为 docker-compose.yml,接着使用 docker-compose up -d 启动应用,和上文提到的一样,我们就能够在浏览器中访问 http://localhost:1080 来浏览和管理“邮件内容”,并通过 1025 端口来进行邮件汇聚操作啦。

最后

和之前提到过的其他的项目一样,接下来我将持续改进这个项目。短时间内,我希望它能够更好的支持 WebHook、并和一些消息推送软件进行打通,更好的支持我的 HomeLab 场景。

如果你对这个项目感兴趣、又比较“心急”的话,可以访问项目源代码:https://github.com/soulteary/maildev 进行 DIY。当然,也欢迎你在项目 issue 中留下你对这个项目的建议和想法。

–EOF