使用 Spring Boot 发送邮件

使用 Spring Boot 发送邮件。

依赖

maven 添加以下库:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
</dependency>

配置

spring:
  mail:
    host: # 比如 <smtp.office365.com>
    username: # 比如 <tblsyx@outlook.com>
    password: # 密码
    port: # 比如 <587>
    protocol: # 协议,比如 <smtp>
    default-encoding: utf-8
    test-connection: true
    properties:
      mail:
        smtp:
          connectiontimeout: 10000
          timeout: 10000
          auth: true
          starttls:
            enable: true
            required: true
          socketFactory:
            port: 587
            class: javax.net.ssl.SSLSocketFactory

代码

注入:

/**
 * 邮件发送线程池
 */
private final ExecutorService mailThreadPool;
private final JavaMailSender mailSender;
/**
 * 邮件列表
 */
private LinkedBlockingQueue<Email> mailSendQueue;

@Autowired
public EmailService(@Qualifier("mailSendingExecutorService") ExecutorService mailThreadPool,
                    JavaMailSender mailSender) {
    this.mailThreadPool = mailThreadPool;
    this.mailSender = mailSender;
}

主要实现:

try {
    if (isValidEmailAddres(email.getEmailAddr())) {
        log.info("Sending mail to {}", email.getEmailAddr());
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true,
                String.valueOf(StandardCharsets.UTF_8));
        messageHelper.setFrom("tblsyx@outlook.com");
        messageHelper.setTo(email.getEmailAddr());
        messageHelper.setSubject("Mail from bolitao.xyz");
        messageHelper.setText("<h3>Hello World!</h3>" + email.getContent(), true);
        mailSender.send(mimeMessage);
        log.info("Sent mail to {} success", email.getEmailAddr());
    } else {
        String errorContent = String.format("Wrong email address: %s", email.getEmailAddr());
        log.error(errorContent);
        throw new MessagingException(errorContent);
    }
} catch (MessagingException | InterruptedException e) {
    log.error("Failed to send email", e);
} catch (Exception e) {
    log.error("Failed to send email", e);
}

问题

Outlook 的问题

在测试中,出现以下异常:

2020-12-10 14:47:27.104 ERROR 17816 --- [    mail-pool-4] x.b.java_starter.service.EmailService    : Failed to send email

org.springframework.mail.MailSendException: Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 432 4.3.2 STOREDRV.ClientSubmit; sender thread limit exceeded [Hostname=xxx.xxx.prod.outlook.com]

我使用的是微软的 Outlook 帐号,查了下,还真是微软的问题,有发送限制。Changes in message store and throttling for concurrent connections - Exchange | Microsoft Docs

The service has various limits to prevent abuse and to ensure fair use. An additional limit is being added. Under the new limit, up to three concurrent connections are allowed to send email messages at the same time.

怎么办?上面的文档给出了三个解决办法。我觉得就第三点有用:换别家的,别用 Outlook toC 用作邮件发送服务。

加载评论