java屏蔽收件人,解决spring boot JavaMailSender部分收件人错误导致发送失败的问题

使用spring boot通常使用spring-boot-starter-mail进行邮件的发送。当进行邮件群发的话,如果一个收件人的地址错误,会导致所有邮件都发送失败。因此我们需要在邮件发送失败的时候把错误的收件人移除,重新发送。

当邮件发送失败的时候会抛出MailSendException,异常信息中包含错误的收件人信息。

主要代码如下:

private void sendMail(List mailList, MimeMessageHelper message){

try{

this.mailSender.send(message.getMimeMessage());

}catch (MailSendException e){

Set tmpInvalidMails = getInvalidAddress(e);

// 非无效收件人导致的异常,暂不处理

if (tmpInvalidMails.isEmpty()){

logger.error(e.getMessage());

return;

}

mailList.removeAll(tmpInvalidMails);

if(mailList.isEmpty()){

logger.error("邮件发送失败,无收件人" + e.getMessage());

return;

}

message.setTo(mailList.toArray(new String[0]));

sendMail(mailList, message)

}

}

捕获邮件发送失败的异常,首先判断是否是收件人无效导致的异常。从异常中解析无效收件人,收件人例表中移除无效的收件人,重新发送邮件。

如何从从异常中获取无效收件人,首先看下JavaMailSenderImpl这个类的doSend方法

f7b4809094e23d2049a8680c6eace2a38cb.jpg

17823e2300191e8959d9e6b959a1b3b9628.jpg

1 protected void doSend(MimeMessage[] mimeMessages, @Nullable Object[] originalMessages) throwsMailException {2 Map failedMessages = new LinkedHashMap<>();3 Transport transport = null;4 try{5 for (int i = 0; i < mimeMessages.length; i++) {6 ...7 //Send message via current transport...

8 MimeMessage mimeMessage =mimeMessages[i];9 try{10 ...11 }12 catch(Exception ex) {13 Object original = (originalMessages != null ?originalMessages[i] : mimeMessage);14 failedMessages.put(original, ex);15 }16 }17 }18 finally{19 try{20 if (transport != null) {21 transport.close();22 }23 }24 catch(Exception ex) {25 if (!failedMessages.isEmpty()) {26 throw new MailSendException("Failed to close server connection after message failures", ex,27 failedMessages);28 }29 else{30 throw new MailSendException("Failed to close server connection after message sending", ex);31 }32 }33 }34

35 if (!failedMessages.isEmpty()) {36 throw newMailSendException(failedMessages);37 }38 }

View Code

当邮件发送过程中遇到异常会保存到failedMessages中,我们需要从中解析收件人无效导致的异常。

接着继续看源码SMTPTransport的rcptTo方法,会去校验每个收件人,通过向服务器发送RCPT TO:,根据响应码来判断收件人是否有效。

ed2a61d1c0929fc0dd1a86a144cf5a31b52.jpg

8cbbbe6d40aae4614ba39d1740d93d67179.jpg

protected void rcptTo() throwsMessagingException {

List valid = newArrayList();

List validUnsent = newArrayList();

List invalid = newArrayList();

...intk;for(k = 0; k < this.addresses.length; ++k) {

sfex= null;

InternetAddress ia= (InternetAddress)this.addresses[k];

String cmd= "RCPT TO:" + this.normalizeAddress(ia.getAddress());if(dsn) {

cmd= cmd + " NOTIFY=" +notify;

}this.sendCommand(cmd);int retCode = this.readServerResponse();switch(retCode) {case 250:case 251:

valid.add(ia);

...break;case 450:case 451:case 452:case 552:

...

validUnsent.add(ia);

...break;case 501:case 503:case 550:case 551:case 553:

...

invalid.add(ia);

...break;default:if (retCode >= 400 && retCode <= 499) {

validUnsent.add(ia);

}else{

...

invalid.add(ia);

}

...

}

}if (sendPartial && valid.size() == 0) {

sendFailed= true;

}intlrc;if(sendFailed) {this.invalidAddr = newAddress[invalid.size()];

invalid.toArray(this.invalidAddr);this.validUnsentAddr = new Address[valid.size() +validUnsent.size()];

k= 0;for(lrc = 0; lrc < valid.size(); ++lrc) {this.validUnsentAddr[k++] =(Address)valid.get(lrc);

}for(lrc = 0; lrc < validUnsent.size(); ++lrc) {this.validUnsentAddr[k++] =(Address)validUnsent.get(lrc);

}

}

...if(sendFailed) {this.logger.fine("Sending failed because of invalid destination addresses");

...throw new SendFailedException("Invalid Addresses", (Exception)mex, this.validSentAddr, this.validUnsentAddr, this.invalidAddr);

}

}

View Code

当收件人无效发送失败会抛出SendFailedException异常,异常中包含收件人是否有效的信息。

因此我们只要从failedMessages查找是否含有SendFailedException,然后从SendFailedException直接得到无效的收件人信息。代码如下:

private Set getInvalidAddress(MailSendException e){

Set mails = new HashSet<>();

for(Exception exception: e.getFailedMessages().values()){

if(exception instanceof SendFailedException){

for(Address address: ((SendFailedException) exception).getInvalidAddresses()){

mails.add(address.toString());

}

}

}

return mails;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值