我有一个后台作业正在运行,每天早晨7:00调用一种方法以将电子邮件发送到特定地址,为此我正在使用Java邮件。
我之所以这样问,是因为有时它会发送MessagingException
(总是在发生此异常的情况下)。这是错误:
nested exception is:
class javax.mail.MessagingException: 530 5.7.1 Client was not authenticated
正如我所说,它只是不时发生;但这有点烦人,因为我必须确保手动发送邮件以防失败。我没有找到发生这种情况的原因,我尝试查找此消息,一些答案表明这是服务器出现问题;不幸的是,我无法控制它。当我手动执行例程时,有时最多需要5或7次尝试才能发送邮件。
所以我想做的是在catch部分中调用相同的方法,而且我还放置了一个计数器来控制尝试次数,以防万一异常被捕获超过5次。
您会建议这种方法吗?感谢您的帮助和答复。
这是我每次抛出MessagingException时试图重新调用的方法的代码:
public void sendMail(String msj, String dest, String asunto, File attachmentSource, int count) {
String to = dest;
String from = "some.user@vw.com.mx";
String host = "someserver.xx.xx.xx";
boolean debug = true;
Properties props = new Properties();
props.put("mail.smtp.host", host);
if (debug) {
props.put("mail.debug", "");
}
Session session = Session.getInstance(props, null);
session.setDebug(debug);
try {
MimeMessage msg = new MimeMessage(session);
msg.setFrom(new InternetAddress(from));
InternetAddress[] address = {new InternetAddress(to)};
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject("Reporte");
msg.setSentDate(new Date());
msg.setText(msj);
MimeBodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(new DataHandler(new FileDataSource(attachmentSource)));
messageBodyPart.setFileName(attachmentSource.getName());
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
msg.setContent(multipart);
Transport.send(msg);
} catch (MessagingException mex) {
Logger.getLogger(SendMSG.class.getName()).log(Level.SEVERE, ("ERROR EN ENVÍO!!!! " + mex.getMessage()));
//THIS IS a TEST TO TRY UNTIL THE MSG IS SENT
count++;
if (count <= 5) {
Logger.getLogger(SendMSG.class.getName()).log(Level.INFO, ("Intento No: " + count + " de 5" + mex.getMessage()));
sendMail(msj, dest, asunto, attachmentSource, count);
} else {
Logger.getLogger(SendMSG.class.getName()).log(Level.SEVERE, ("No. de Intentos excedido " + count + " SALIR DE MÉTODO" + mex.getMessage()));
}
mex.printStackTrace();
}
}
答案 0 :(得分:3)
您的解决方案很好,但是很混乱。我将重试和发送分开。
public boolean sendMail(String msj, String dest, String asunto, File attachmentSource, int retries) {
for (int i = 0; i< retries; i++){
if (sendMail(msj, dest, asunto, attachmentSource)){
return true;
}
}
return false;
}
public boolean sendMail(String msj, String dest, String asunto, File attachmentSource) {
try {
...
return true;
} catch (Exception ex) {
return false;
}
}
它的作用与代码基本相同,但提高了可读性。
答案 1 :(得分:0)
想出一种将两件事分开的方法:执行方法的主要逻辑和发生故障时的行为。如果可以编写接口,则可以使用ExceptionHandler
的类型,在其中声明方法handleFault
(例如)。然后,在您的主类中,您可以注入ExceptionHandler
的某些特定实现,以便在发生故障时决定要怎么做。
这将使测试变得更加容易,因为您可以从一个简单的测试对象中替换“实时”或“生产”或我们所谓的行为,而您只想检查是否处理了错误的案例。
我认为值得研究一下马丁·福勒(Martin Fowler)在这里描述的 ciruit断路器模式:https://martinfowler.com/bliki/CircuitBreaker.html
您可以有一个单独的策略来处理错误,重试模板(重试次数,两次重试之间的时间等)。
答案 2 :(得分:0)
我想假设错误取决于时间。由于它有时会发生,而有时却不会。考虑到这一点,我建议在count++
像这样:
synchronized (this)
{
this.wait(count*1000);//delay after each error
}
答案 3 :(得分:0)
其他答案中有一些有用的建议,但是我认为问题的核心部分是您从不对服务器进行身份验证。除非您使用不需要身份验证的本地服务器,否则我不知道它的工作原理。
如JavaMail FAQ中所述,将您的Transport.send呼叫替换为
Transport.send(msg, username, password);
用户名和密码是登录邮件服务器的凭据。