一、背景
1、框架和语言:SpringMVC、Java
2、使用的是Outlook邮箱服务器,由外地公司邮箱管理员管理(不好沟通)。
3、需求:系统根据业务需求自动发邮件到员工邮箱。
二、走的弯路
刚开始我直接用以前用过的org.springframework.mail.javamail.JavaMailSenderImpl实现,报错类似
Caused by: javax.mail.AuthenticationFailedException: 535 5.7.139 Authentication unsuccessful, SmtpClientAuthentication is disabled for the Tenant. Visit https://XXXX for more information. [HK2PR04CA0071.apcprd04.prod.outlook.com]
AI问了一通大概意思是需要邮箱管理员开启一下SMTP协议,使能够启用身份验证的客户SMTP提交(SMTP Auth)。
找了管理员,他也找不到这个设置,没办法开启。又搜索+AI问了一通得知Outlook邮箱的安全验证问题,可以用 exchange协议解决。
三、核心代码
pom.xml添加ews包
<dependency>
<groupId>com.microsoft.ews-java-api</groupId>
<artifactId>ews-java-api</artifactId>
<version>2.0</version>
</dependency>
package ...
import ....
@Component("eMailHandler")
public class EMailHandler {
private static Logger logger = LoggerFactory.getLogger(EMailHandler.class);
public boolean sendEMail(MailModel mailModel){
try{
ExchangeService service = new ExchangerServiceSSLVerify(ExchangeVersion.Exchange2010_SP2);
ExchangeCredentials credentials = new WebCredentials(mailModel.getMailFrom(), mailModel.getMailPassword());
service.setCredentials(credentials);
service.setUrl(new URI("https://" + mailModel.getMailHost() + "/EWS/Exchange.asmx"));
// service.setTraceEnabled(true); //是否启用ExchangeService的跟踪功能,用于调试
EmailMessage msg = new EmailMessage(service);
msg.setSubject(mailModel.getSubjectName());
// 设置邮件内容并添加签名
StringBuilder contentWithSignature = new StringBuilder(mailModel.getContent());
contentWithSignature.append("<br/><br/>");
contentWithSignature.append("------------------------------------<br/>");
if (mailModel.getSigns() != null && mailModel.getSigns().length > 0) {
for (String signText : mailModel.getSigns()) {
contentWithSignature.append(signText).append("<br/>");
}
}
msg.setBody(MessageBody.getMessageBodyFromText(contentWithSignature.toString()));
for (String mailTo : mailModel.getMailTo()){
msg.getToRecipients().add(mailTo); //接受人邮箱
}
msg.sendAndSaveCopy(); //发送现有电子邮件并保存到已发送
} catch (Exception e) {
logger.error("******sendEMail邮件发送异常*******", e);
return false;
}
return true;
}
}
mailModel.getMailFrom() 负责发送邮件的邮箱地址
mailModel.getMailPassword()) 邮箱账号密码
mailModel.getMailHost() 邮箱服务器
mailModel.getSubjectName() 标题/主题
mailModel.getContent() 内容
mailModel.getSigns() 签名
mailModel.getMailTo() 邮件接收人邮箱地址数组
四、遇到的错误
在网上找到的代码,其中有一行在创建WebCredentials的时候使用的构造函数是三个参数的,最后一位是mailModel.getDomain()是邮箱服务器域名:
ExchangeCredentials credentials = new WebCredentials(mailModel.getMailFrom(), mailModel.getMailPassword(),mailModel.getDomain());
报错如下:
可能域名配置得不对,也不清楚应该是多少,直接去掉这个参数就没问题了!
五、部署服务遇到的问题
把java程序部署到了内网环境,无法访问互联网地址的邮箱服务器,改成使用内网的IP地址https://XXXX/EWS/Exchange.asmx(XXXX替换成IP地址)
报错:microsoft.exchange.webservices.data.core.exception.service.remote.ServiceRequestException: The request failed. The request failed. Connect to XXXXX:443 [/1XXXXXX] failed: Connection refused: connect
表明应用程序尝试通过 EWS(Exchange Web Services)连接到 Exchange 服务器时失败,具体原因是无法建立到 XXXX:443
的连接(连接被拒绝)
以下是问AI得到的方案选择:
现状是邮箱服务器我们没有权限管理,开不了443端口,如何走互联网过去?
首先,验证网络连通性:
在部署程序的服务器上打开命令提示符执行命令(马赛克的地址是邮箱服务器互联网地址)
这表明内网DNS服务器无法解析该域名,可能是DNS配置问题或内网防火墙阻止了DNS查询。
其次,测试解析Exchange服务的公网域名
最后,把URI:https://XXXX/EWS/Exchange.asmx(XXXX替换成公网IP)。
可以在部署服务器上的浏览器输入框直接访问URI,测试是否能够登陆邮箱服务器。