第三方框架整合

Vert.x 邮件客户端 (vertx-mail-client)

Vert.x 邮件客户端是针对 SMTP 协议的纯异步、非阻塞式邮件发送实现,支持连接本机邮件服务(如 Postfix)或第三方外部邮件服务商(如 Gmail、QQ 邮箱、163 等)。

客户端全面支持主流安全认证方式(如 DIGEST-MD5、NTLM),完整支持 STARTTLS 与 SSL/TLS 加密,并内建高性能连接池以实现持久连接的高效复用。

要在项目中使用该组件,请在构建描述文件中添加以下依赖:

  • Maven(在 pom.xml 中):

<dependency>
  <groupId>io.vertx</groupId>
  <artifactId>vertx-mail-client</artifactId>
  <version>5.2.1</version>
</dependency>
  • Gradle(在 build.gradle 文件中):

compile 'io.vertx:vertx-mail-client:5.2.1'

创建邮件客户端

你可以通过创建邮件客户端在本地 JVM 中发起 SMTP 连接发送邮件。

客户端通过配置对象进行初始化。默认空配置会自动尝试连接 localhost:25 端口(适用于运行在 Linux 本机且部署有 Postfix 等代理的常见场景)。

客户端内建了 SMTP 连接池机制,消除了每次发送邮件时建立 TCP 连接、协商 TLS 握手及登录验证的昂贵开销(可通过设置 keepAlive = false 关闭连接池)。客户端支持共享(Shared)与非共享两种模式:若使用共享模式,拥有相同标识符(Identifier)的客户端将共用同一个底层连接池。

MailConfig config = new MailConfig();
MailClient mailClient = MailClient
  .createShared(vertx, config, "exampleclient");

首次调用 MailClient.createShared 时会以传入的配置真正构建连接池;后续相同标识符的调用将返回复用该池的客户端实例,传入的配置项将被忽略。若省略标识符参数,系统将自动创建默认共享连接池。请注意共享连接池的生命周期与作用域绑定在当前 Vert.x 实例之内。

非共享模式的客户端可通过省略标识符直接创建:

MailConfig config = new MailConfig();
MailClient mailClient = MailClient.create(vertx, config);

以下是连接需要 TLS 认证登录的外部邮件服务器的典型配置示例:

MailConfig config = new MailConfig();
config.setHostname("mail.example.com");
config.setPort(587);
config.setStarttls(StartTLSOptions.REQUIRED);
config.setUsername("user");
config.setPassword("password");
MailClient mailClient = MailClient.create(vertx, config);

动态凭据提供者

你可以通过 MailClientBuilder 为客户端注入异步 Supplier 函数来动态获取用户名与密码,这非常适合需要定期密码轮转或对接密钥管理系统的企业生产环境:

MailConfig config = new MailConfig()
  .setHostname("mail.example.com")
  .setPort(587)
  .setStarttls(StartTLSOptions.REQUIRED);
MailClient mailClient = MailClient.builder(vertx)
  .with(config)
  .withCredentialsSupplier(() -> {
    Future<UsernamePasswordCredentials> future = retrieveCredentialsAsync();
    return future;
  })
  .build();
当提供了动态凭据函数后,在 MailConfig 中静态配置的用户名和密码将被自动忽略。

发送邮件

客户端初始化就绪后即可执行邮件发送。所有发送操作在 Vert.x 中均为全异步执行,当邮件操作完成或失败时触发回调。你可以并发发起多个发送任务,底层连接池会自动限流并按队列排队调度。

邮件消息在底层构造为 MIME 报文。MailMessage 提供了 from、to、cc、bcc、subject、text、html 等丰富的属性。根据设定的内容,系统将自动生成规范的 MIME 结构:

MailMessage message = new MailMessage();
message.setFrom("user@example.com (示例用户)");
message.setTo("recipient@example.org");
message.setCc("另一个用户 <another@example.net>");
message.setText("这是邮件的纯文本正文");
message.setHtml("这是富文本 HTML 内容:<a href="https://vertx.net.cn">Vert.x 中文网</a>");

附件可以通过 MailAttachment 封装 Buffer 中的二进制数据进行上传:

MailAttachment attachment = MailAttachment.create();
attachment.setContentType("text/plain");
attachment.setData(Buffer.buffer("这是附件文件内容"));

message.setAttachment(attachment);

针对内嵌图片附件,可以在 HTML 中通过 <img src="cid:contentid@domain"> 进行引用,以在正文中直接内联渲染图片:

MailAttachment attachment = MailAttachment.create();
attachment.setContentType("image/jpeg");
attachment.setData(Buffer.buffer("图片二进制数据"));
attachment.setDisposition("inline");
attachment.setContentId("<image1@example.com>");

message.setInlineAttachment(attachment);

发送邮件的异步调用方式如下:

mailClient.sendMail(message)
  .onSuccess(System.out::println)
  .onFailure(Throwable::printStackTrace);

DKIM 邮件数字签名 (DomainKeys Identified Mail)

模块原生支持 DKIM 签名,通过密码学签名证明邮件发送方的真实身份,防范垃圾邮件拦截与钓鱼篡改:

DKIMSignOptions dkimSignOptions = new DKIMSignOptions();
dkimSignOptions.setPrivateKey("PKCS8 私钥的 Base64 编码字符串");
dkimSignOptions.setAuid("identifier@example.com");
dkimSignOptions.setSelector("selector");
dkimSignOptions.setSdid("example.com");
MailConfig config = new MailConfig()
  .setDKIMSignOption(dkimSignOptions)
  .setEnableDKIM(true);

MailClient mailClient = MailClient.createShared(vertx, config);

配置后,每次调用 mailClient.sendMail 时均会自动计算哈希并在邮件标头中附加 DKIM-Signature。

DKIM 附件流缓存机制

由于 DKIM 签名需要对包括附件在内的完整邮件体进行哈希运算,来自响应式流 ReadStream 的附件数据无法单遍多次读取,因此客户端提供了 2 种缓存策略:

  • 内存缓存:默认情况下附件流缓冲在内存中以便后续发送。

  • 临时文件缓存:针对大附件,可通过系统属性 -Dvertx.mail.attachment.cache.file=true 启用磁盘临时文件缓存,发送完毕后临时文件将自动安全销毁。

关键数据对象说明

MailMessage 属性字典

  • from:发件人地址与 MAIL FROM 字段

  • to:收件人地址列表与 RCPT TO 字段

  • cc / bcc:抄送与密送地址

  • bounceAddress:退信通知错误接收地址

  • subject:邮件主题

  • text:纯文本正文内容

  • html:富文本 HTML 正文内容

  • attachment:独立附件列表

  • inlineAttachment:正文内联附件列表

  • headers:自定义 MIME 标头集合

MailConfig 核心配置项

  • hostname:SMTP 服务器域名或 IP(默认 localhost)

  • port:连接端口(默认 25,SSL 通常为 465,STARTTLS 通常为 587)

  • startTLS:STARTTLS 选项(DISABLED / OPTIONAL / REQUIRED,默认 OPTIONAL)

  • login:登录认证模式(DISABLED / NONE / REQUIRED)

  • username / password:认证登录凭据

  • ssl:是否在建连时即启用直接 SSL 连接(默认 false)

  • keepAlive:是否启用连接池(默认 true)

  • maxPoolSize:最大活跃并发连接数(默认 10)

  • pipelining:若 SMTP 服务端支持,是否启用流水线批量指令加速(默认 true)

  • keepAliveTimeout:连接池空闲保活超时时长(默认 300 秒)