将 JavaMail 与 TLS 一起使用

Posted

技术标签:

【中文标题】将 JavaMail 与 TLS 一起使用【英文标题】:Using JavaMail with TLS 【发布时间】:2010-09-29 12:09:56 【问题描述】:

我在 SO 上发现了其他几个关于 JavaMail API 和通过 SMTP 服务器发送邮件的问题,但没有一个讨论过使用 TLS 安全性。我正在尝试使用 JavaMail 通过我的工作 SMTP 邮件服务器向自己发送状态更新,但它需要 TLS,而且我在网上找不到任何关于如何使用 JavaMail 访问需要 TLS 加密的 SMTP 服务器的示例。有人可以帮忙吗?

【问题讨论】:

【参考方案1】:

我们的产品中实际上有一些通知代码,如果可用,它会使用 TLS 发送邮件。

您需要设置 Java Mail 属性。您只需要 TLS,但如果您的 SMTP 服务器使用 SSL,则可能需要 SSL。

Properties props = new Properties();
props.put("mail.smtp.starttls.enable","true");
props.put("mail.smtp.auth", "true");  // If you need to authenticate
// Use the following if you need SSL
props.put("mail.smtp.socketFactory.port", d_port);
props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtp.socketFactory.fallback", "false");

然后,您可以将其传递给 JavaMail 会话或任何其他会话实例化器,例如 Session.getDefaultInstance(props)

【讨论】:

非常感谢!从字面上看,我所做的只是添加行 props.put("mail.smtp.starttls.enable","true");到我的代码,它工作得很好! 请注意,现代 java.mail 不需要设置套接字工厂:***.com/questions/17581066/…【参考方案2】:

好帖子,行

props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
如果 SMTP 服务器使用 SSL 身份验证,则

是强制性的,就像 GMail SMTP 服务器一样。但是,如果服务器使用 Plaintext Authentication over TLS,则它不应该存在,因为 Java Mail 会抱怨初始连接是纯文本的。

还要确保您使用的是最新版本的 Java Mail。最近我使用了以前项目中的一些旧 Java Mail jars 并且无法使代码工作,因为登录过程失败。升级到最新版本的Java Mail后,错误原因就清楚了:是javax.net.ssl.SSLHandshakeException,在旧版本的lib中没有抛出。

【讨论】:

【参考方案3】:

上面示例中的设置不适用于我使用的服务器 (authsmtp.com)。我不断收到此错误:

javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?

我删除了 mail.smtp.socketFactory 设置,一切正常。最终设置是这样的(未使用 SMTP 身份验证,我在其他地方设置了端口):

java.util.Properties props = new java.util.Properties();
props.put("mail.smtp.starttls.enable", "true");

【讨论】:

【参考方案4】:

只需使用以下代码。通过 Java 发送电子邮件真的很有用,而且很有效:

import java.util.*;
import javax.activation.CommandMap;
import javax.activation.MailcapCommandMap;
import javax.mail.*;
import javax.mail.Provider;
import javax.mail.internet.*;

public class Main 

    public static void main(String[] args) 
            final String username="your@gmail.com";
            final String password="password";
            Properties prop=new Properties();
            prop.put("mail.smtp.auth", "true");
            prop.put("mail.smtp.host", "smtp.gmail.com");
            prop.put("mail.smtp.port", "587");
            prop.put("mail.smtp.starttls.enable", "true");

            Session session = Session.getDefaultInstance(prop,
          new javax.mail.Authenticator() 
            protected PasswordAuthentication getPasswordAuthentication() 
                return new PasswordAuthentication(username, password);
          
        );
          try 
                 String body="Dear Renish Khunt Welcome";
                 String htmlBody = "<strong>This is an HTML Message</strong>";
                 String textBody = "This is a Text Message.";
         Message message = new MimeMessage(session);
         message.setFrom(new InternetAddress("your@gmail.com"));
                 message.setRecipients(Message.RecipientType.TO,InternetAddress.parse("receiver@gmail.com"));
        message.setSubject("Testing Subject");
        MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
        mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);
            message.setText(htmlBody);
                        message.setContent(textBody, "text/html");
            Transport.send(message);

            System.out.println("Done");

         catch (MessagingException e) 
            e.printStackTrace();
        

    


【讨论】:

【参考方案5】:

使用Simple Java Mail 5.0.0 (simplejavamail.org) 非常简单,该库将为您处理所有 Session 属性。

以下是使用 Google 的 SMTP 服务器的示例:

Email email = EmailBuilder.startingBlank()
        .from("lollypop", "lol.pop@somemail.com")
        .to("C.Cane", "candycane@candyshop.org")
        .withSubject("hey")
        .withPlainText("We should meet up!")
        .withHTMLText("<b>We should meet up!</b>")
        .buildEmail();

MailerBuilder.withSMTPServer("smtp.gmail.com", 25, "user", "pass", SMTP_TLS)
        .buildMailer()
        .sendMail(email);

MailerBuilder.withSMTPServer("smtp.gmail.com", 587, "user", "pass", SMTP_TLS)
        .buildMailer()
        .sendMail(email);

MailerBuilder.withSMTPServer("smtp.gmail.com", 465, "user", "pass", SMTP_SSL)
        .buildMailer()
        .sendMail(email);

如果您启用了双因素登录,则需要从您的 Google 帐户生成application specific password。

【讨论】:

【参考方案6】:

作为一个小提示,当我在上面的示例中根据 javamail 的示例将 smtp 更改为 smtps 时,它才开始对我起作用(请参阅 smtpsend.java,https://github.com/javaee/javamail/releases/download/JAVAMAIL-1_6_2/javamail-samples.zip,选项 -S)。

我的结果代码如下:

Properties props=new Properties();
props.put("mail.smtps.starttls.enable","true");
// Use the following if you need SSL
props.put("mail.smtps.socketFactory.port", port);
props.put("mail.smtps.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.put("mail.smtps.socketFactory.fallback", "false");
props.put("mail.smtps.host", serverList.get(randNum));
Session session = Session.getDefaultInstance(props);

smtpConnectionPool = new SmtpConnectionPool(
    SmtpConnectionFactories.newSmtpFactory(session));
    
final ClosableSmtpConnection transport = smtpConnectionPool.borrowObject();
...
transport.sendMessage(message, message.getAllRecipients());

【讨论】:

【参考方案7】:

我刚刚花了很多时间弄清楚如何使用 JavaMail 通过 gmail 或 office365 发送电子邮件。我在faq 中找不到答案,但得到了javadoc 的帮助。

如果你忘记了props.put("mail.smtp.starttls.enable","true"),你会得到com.sun.mail.smtp.SMTPSendFailedException: 451 5.7.3 STARTTLS is required to send mail

如果你忘记了props.put("mail.smtp.ssl.protocols", "TLSv1.2");,你会得到javax.mail.MessagingException: Could not convert socket to TLS;No appropriate protocol (protocol is disabled or cipher suites are inappropriate)。显然这仅对 JavaMail 1.5.2 及更早版本是必需的。

这是我让它工作所需的最少代码:

import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendEmail 
    public static void main(String[] args) 
        Properties props = new Properties();
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.starttls.enable","true");
        // smtp.gmail.com supports TLSv1.2 and TLSv1.3
        // smtp.office365.com supports only TLSv1.2
        props.put("mail.smtp.ssl.protocols", "TLSv1.2");
        props.put("mail.smtp.host", "smtp.office365.com");
        props.put("mail.smtp.port", "587");
        
        Session session = Session.getInstance(props, new Authenticator() 
            @Override
            protected PasswordAuthentication getPasswordAuthentication() 
                return new PasswordAuthentication("test@example.com", "******");
            
        );
        
        try 
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress("sender@example.com"));
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse("recipient@example.com"));
            message.setSubject("You got mail");
            message.setText("This email was sent with JavaMail.");
            Transport.send(message);
            System.out.println("Email sent.");
         catch (MessagingException e) 
            throw new RuntimeException(e);
        
    

【讨论】:

以上是关于将 JavaMail 与 TLS 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

Javamail 无法将套接字转换为 TLS GMail

JavaMail 问题或错误?

java jar包收集

如何使 Windows 商店应用程序与 TLS 1.2 一起使用?

Java:将 DKIM 私钥从 RSA 转换为 DER for JavaMail

用过的jar包整合