邮件发送失败IllegalStateException: The mail session is already initialized解决

勤奋不是嘴上说说而已,而是实际的行动,在勤奋的苦度中持之以恒,永不退却。业精于勤,荒于嬉;行成于思,毁于随。在人生的仕途上,我们毫不迟疑地选择勤奋,她是几乎于世界上一切成就的催产婆。只要我们拥着勤奋去思考,拥着勤奋的手去耕耘,用抱勤奋的心去对待工作,浪迹红尘而坚韧不拔,那么,我们的生命就会绽放火花,让人生的时光更加的闪亮而精彩。

导读:本篇文章讲解 邮件发送失败IllegalStateException: The mail session is already initialized解决,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

概述

很【简单】的一个问题,之前从来没有遇到过;第一反应是搜索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后就不能再去设置更新其端口号信息。

拓展

IllegalStateException: The MimeMessage is already built

与此相似的另一个问题,参考(java.lang.IllegalStateException: The MimeMessage is already built

先构建Mime消息体,即调用buildMimeMessage()方法,然后发生Mime消息,即调用sendMimeMessage()方法,前者只能调用一次,后者可以多次调用。

如果多次调用前者,则报错IllegalStateException: The MimeMessage is already built

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/142156.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!