java - 如何发送带有错误捕获和报告的 Java 邮件

标签 java sendmail

我的 Windows Java 应用程序需要向多个收件人发送个性化电子邮件。用户必须提供主机、端口、用户名、密码,当然还有收件人地址。如果出现问题,我希望有有意义的报告,例如“连接失败。检查用户名和密码”。如果连接失败,则不应尝试发送。此外,还应验证电子邮件地址的格式,如果无效则跳过。

我查看了许多示例,它们帮助我创建了下面的工作代码。它很好地告诉用户出了什么问题,例如主机不存在、用户名或密码错误等,但充其量也是不优雅的。

我知道 SendFailedException 并希望它是我所需要的,但尚未找到一个完整且简单的示例来向我展示如何满足我的需求。到目前为止我看到的例子要么太简单,要么太复杂并且嵌入到大型项目中。我希望有人能告诉我我是否走在正确的道路上,或者如何改进它。

这是我的代码(2019 年 9 月 2 日修订):

public class SimpleMail2 {
private static String host;
private static String port;
private static String username;
private static String password;
private static String from;

private void sendAction(){
    host =  "smtp.gmail.com"; //"nx.dnslinks.com"; //
    port = "587";
    username = "jagman653@gmail.com"; //eds653@concoursbuilder.us"; 
    password =  "xxxxx"; 
    from = "usere123@concoursbuilder.us";
    String [] recipients = {"usera123@concoursbuilder.us", // Good
                            "userb123@concoursbuilder-us", // Valid according to RFC 822, but deemed INVALID for typical recipients.
                            "userc123concoursbuilder.us",  // Invalid format... no @
                            "userX123@concoursbuilder.us", // Valid format but no such mailbox at concoursbuilder.us
                            "hurt123@aol-com",  // Invalid format
                            "userc123@concoursbuilder.us"}; // Good

    // Prevalidate all recipient addresses
    ArrayList<String> goodAddrs = new ArrayList<>();
    System.out.println("Prevalidate email addresses.");
    for(String recip : recipients){
        System.out.println("recip: " + recip);
        boolean isOK = validateEmail(recip); //Valid according to RFC 822, but deemed INVALID for typical recipients.
        if(isOK){
            String msg;
            goodAddrs.add(recip);
            msg = "Good email address: " + recip;
            System.out.println(msg);
        } else {
            String msg;
            msg = " Bad email address: " + recip;
            System.out.println(msg);
        }
    }
    String[] goodAddrAry = new String[goodAddrs.size()];
    goodAddrAry = goodAddrs.toArray(goodAddrAry);
    int result = senderToAll(goodAddrAry);
    System.out.println("There were " + result + " successful sends and " + (recipients.length - result) + " failures.\n");
}

private int senderToAll(String [] recipients){
    System.out.println("Starting senderToAll\n\n");
    Properties props = new Properties();
    props.put("mail.transport.protocol", "smtp");
    props.put("mail.smtp.host", host);
    props.put("mail.smtp.port", port);
    props.put("mail.smtp.user", username);
    props.put("mail.smtp.password", password);
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", "true"); //TLS
    // Note that an authenticator is incorporated in the session instance. 
    Session mailSession = Session.getInstance(props, new javax.mail.Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(username, password);
                }
            });

    Transport transport = null;
    int successfulSends = 0;
    try {
        transport = mailSession.getTransport();
    } catch (NoSuchProviderException ex) {
        String msg = ex.getMessage();
        System.out.println(msg  + "\n");
        Logger.getLogger(SimpleMailDialog.class.getName()).log(Level.SEVERE, null, ex);
        return successfulSends; 
    }
    try{
        if(!transport.isConnected())
            transport.connect();
    } catch ( javax.mail.MessagingException mex){
       String msg = mex.getMessage();
       String msg2;
       if(msg.contains("Unknown SMTP host") || msg.contains("DNS Error")) {
           msg2 =  "MessagingException while trying to connect: Could not connect. Check eMail host name" ;
           System.out.println(msg2);
       } else if(msg.contains("Could not connect to SMTP host")){
           msg2 =  "MessagingException while trying to connect: Could not connect. Check eMail host name & port" ;
           System.out.println(msg2);
       }
       else if(msg.contains("authentication failed") || msg.contains("535")){
            msg2 =  "MessagingException while trying to connect: Authentication failed. Check user eMail address & password.";
            System.out.println(msg2);
       }  else {
            msg2 =  "MessagingException while trying to connect: " + mex.getMessage();
            System.out.println(msg2);
       } 
       return successfulSends; // no sends will be attempted
    }
    for(String recip : recipients){
        MimeMessage message = new MimeMessage(mailSession);
        try {
            message.setContent("This is sent to " + recip + " using SimpleMail", "text/plain");
        } catch (MessagingException ex) {
            String msg2 =  "MessagingException while trying to set content: " + ex.getMessage();
            System.out.println(msg2);
            Logger.getLogger(SimpleMailDialog.class.getName()).log(Level.SEVERE, null, ex);
        }
        boolean result = true;
        try {
            result = senderToSingle(message, transport, recip, from);
        } catch (Exception ex) {
            String msg2 =  "Exception while sending to " + recip + "message: " + ex.getMessage();
            System.out.println(msg2);
            Logger.getLogger(SimpleMailDialog.class.getName()).log(Level.SEVERE, null, ex);
            result = false;
        }
        if(result){
           String msg = "Sent to " + recip;
           System.out.println(msg);
           successfulSends++;
        } else {
           String msg = "NOT Sent to " + recip;
           System.out.println(msg);
        }
   }

    if(transport.isConnected()){
        try {
            transport.close();
        } catch (MessagingException ex) {
           String msg = "Failed to close connection";
           System.out.println(msg);
           Logger.getLogger(SimpleMailDialog.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
   return successfulSends; 
}


public static boolean senderToSingle(MimeMessage message, Transport transport, String recip, String from) throws Exception{
    message.setFrom(new InternetAddress(from)); 
    InternetAddress[] toAddrs = InternetAddress.parse(recip);
    InternetAddress[] replyToAddrs = InternetAddress.parse(from);
message.setRecipient(javax.mail.Message.RecipientType.TO, toAddrs[0]);
    message.setReplyTo(replyToAddrs);
    Address[] toRecips = message.getRecipients(javax.mail.Message.RecipientType.TO);
    String msg2;
    try {
        transport.sendMessage(message, toRecips);
    } catch (MessagingException ex){
        String msg = ex.getMessage();
        if(msg.contains("Invalid Address") || msg.contains("User unknown")){
            msg2 =  "MessagingException: " + recip + " is an invalid address. ";
            System.out.println(msg2);
            return false;
        } else if(msg.contains("Mailbox unavailable") ){
            msg2 =  "MessagingException:  mailbox unavailable while attempting to send . " + recip ;
            System.out.println(msg2);
            return false;
        } else {
            msg2 =  "MessagingException: " +  msg + " for recipient " + recip ;
            System.out.println(msg2);
            return false;
        }
    }  
    return true;
}


public boolean validateEmail(String email) {
    boolean isValid = false; // this value never used
    try {
        InternetAddress internetAddress = new InternetAddress(email, true); // strict
        internetAddress.validate(); // this throws AddressException if it doesn't meet RFC822 rules
        // There is a "@" since otherwise it would have thrown AddressException
        //Check to be sure it also has a DOT after the @ ... i.e., the most common form of address
        String[] splitArray = email.split("@");
        if(splitArray[1].contains(".")) isValid = true;
    } catch (AddressException e) {
        System.out.println("AddressException in MyJavaUtils validateEmail(). Bad eMail address: " + email);
        return  false;
    }
    return isValid;
}

public static void main(String args[]) {
    /* Set the Nimbus look and feel */
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
    /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
     * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
     */
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(SimpleMailDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(SimpleMailDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(SimpleMailDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(SimpleMailDialog.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //</editor-fold>

    /* Create and display the dialog */
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            SimpleMail2 smt = new SimpleMail2();
            smt.sendAction();
        }
    });
}    

}

最佳答案

终于在这里找到了更完整的SendFailedException用法示例: https://javaee.github.io/javamail/#Samples 。请参阅 Max Spivak 的公共(public)交通。根据我的需要,我必须修改它来进行身份验证。效果很好,但我很好奇他在发送消息后包含线程 sleep 。

关于java - 如何发送带有错误捕获和报告的 Java 邮件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57750265/

相关文章:

java - 将 SimpleDateFormat 转换为 DateTimeFormatter

javascript - 如何使用后端 Node JS 服务器的 sendmail 从 Webix 应用程序发送电子邮件

linux - 如何配置一个vps服务器在linux上发送邮件

java - 选择成员变量条件为真的所有bean

java - 将 List<Object> 转换为 List<String> 而不使用 for?

java - Spring启动RabbitMQ主机字符串格式

java - Junit:在没有实例的情况下调用私有(private)方法

c# - 使用带有 Mandrill 的 Smtp 客户端发送电子邮件

sql - xp_smtp_sendmail 空格随机添加到html

sendmail - 我如何链接 digitalocean、namecheap 和发送网格来发送邮件,这是我当前的域名和 DNS 配置