邮件发送失败IllegalStateException: The mail session is already initialized解决
概述
很【简单】的一个问题,之前从来没有遇到过;第一反应是搜索Google,没有找到解决方案。木有办法,只好去看源码;看到源码后,很容易就能解决问题。还是记录一下此文。同时,告诫一下自己,遇到报错不要第一反应就去查Google,先看看源码。
问题
ELK以及IDEA 控制台记录如下报错日志:
c.x.c.web.controller.subscribe.BoardJobController [sendEmail:145] 发送邮件失败
java.lang.IllegalStateException: The mail session is already initialized
at org.apache.commons.mail.Email.checkSessionAlreadyInitialized(Email.java:1940)
at org.apache.commons.mail.Email.setSmtpPort(Email.java:529)
at com.johnny.common.services.impl.BoardJobServiceImpl.lambda$sendEmail$3(BoardJobServiceImpl.java:367)
at java.util.ArrayList.forEach(ArrayList.java:1249)
at com.johnny.common.services.impl.BoardJobServiceImpl.sendEmail(BoardJobServiceImpl.java:296)
at com.johnny.web.controller.subscribe.BoardJobController.sendEmail(BoardJobController.java:141)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:665)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
使用的工具包:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.4</version>
</dependency>
出错的代码片段
toList.forEach(toEmail -> {
// 遍历每个收件人,对每个收件人发送邮件
HtmlEmail email = new HtmlEmail();
email.setCharset("utf-8");
try {
email.setHtmlMsg("");
// 数据库查询邮箱
EmailSftpModel mailServer = emailSftpMapper.getOneMailRand();
email.setAuthentication(mailServer.getSmtpUsername(), mailServer.getSmtpPassword());
email.setFrom(mailServer.getSmtpFrom());
email.setSubject(subject);
email.addTo(toEmail);
if ("smtp.partner.outlook.cn".equals(mailServer.getSmtpHost())) {
email.setStartTLSEnabled(true);
Properties prop = new Properties();
prop.setProperty("mail.smtp.host", mailServer.getSmtpHost());
if (StringUtils.isNotEmpty(mailServer.getSmtpPort())) {
prop.setProperty("mail.smtp.port", mailServer.getSmtpPort());
}
prop.setProperty("mail.smtp.auth", "true");
prop.setProperty("mail.smtp.starttls.enable", "true");
prop.setProperty("mail.smtp.ssl.protocols", "TLSv1.2");
DefaultAuthenticator authenticator = new DefaultAuthenticator(mailServer.getSmtpUsername(), mailServer.getSmtpPassword());
Session session = Session.getInstance(prop, authenticator);
email.setMailSession(session);
}
if (!Strings.isNullOrEmpty(mailServer.getSmtpPort())) {
// 报错行
email.setSmtpPort(Integer.parseInt(mailServer.getSmtpPort()));
}
email.setHostName(mailServer.getSmtpHost());
email.send();
} catch (EmailException e) {
logger.error("发送邮件失败,收件人:" + toEmail, e);
sendErrLog.append("发送邮件失败,收件人:").append(toEmail).append(e.getMessage()).append(";");
}
});
报错代码行:email.setSmtpPort(Integer.parseInt(mailServer.getSmtpPort()));
。查看org.apache.commons.mail.Email
源码:
public abstract class Email {
public void setSmtpPort(final int aPortNumber)
{
checkSessionAlreadyInitialized();
if (aPortNumber < 1)
{
throw new IllegalArgumentException(
"Cannot connect to a port number that is less than 1 ( " + aPortNumber + " )");
}
this.smtpPort = Integer.toString(aPortNumber);
}
private void checkSessionAlreadyInitialized()
{
if (this.session != null)
{
throw new IllegalStateException("The mail session is already initialized");
}
}
}
解决方案,将如下代码片段
// fix IllegalStateException: The mail session is already initialized
if (!Strings.isNullOrEmpty(mailServer.getSmtpPort())) {
email.setSmtpPort(Integer.parseInt(mailServer.getSmtpPort()));
}
email.setHostName(mailServer.getSmtpHost());
提前到:email.setMailSession(session);
之前。
即放在if ("smtp.partner.outlook.cn".equals(mailServer.getSmtpHost())) {
之前。
言外之意,就是发送邮件的HtmlEmail API需要有一个Session,而这个Session的实例化(Session session = Session.getInstance(prop, authenticator);
)需要在prop
里面配置端口号信息,如果没有配置端口号,则使用默认的端口。HtmlEmail设置好Session后就不能再去设置更新其端口号信息。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix