Javamail 和 STARTTLS 不能在不同的平台上工作

Javamail and STARTTLS not working on different platforms

我创建了一个使用 STARTLS 发送电子邮件的示例。 运行 它在不同域中托管的 3 个不同 windows 版本上运行,一切正常。

奇怪的是,当我 运行 它在 Ubuntu 服务器 14.02 LTS 上时它不起作用。没有防火墙阻止,java 应用程序二进制文件相同。

这是代码:

// Port we will connect to on the Amazon SES SMTP endpoint. We are choosing port 25 because we will use
// STARTTLS to encrypt the connection.
static final int PORT = 25;

public static void main(String[] args) throws Exception {

    // Create a Properties object to contain connection configuration information.
    Properties props = System.getProperties();
    props.put("mail.transport.protocol", "smtp");
    props.put("mail.smtp.port", PORT);

    // Set properties indicating that we want to use STARTTLS to encrypt the connection.
    // The SMTP session will begin on an unencrypted connection, and then the client
    // will issue a STARTTLS command to upgrade to an encrypted connection.
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.starttls.enable", "true");
    props.put("mail.smtp.starttls.required", "true");
    props.put("mail.smtp.ssl.enable", "false");
    props.put("mail.debug", "true");

    // Create a Session object to represent a mail session with the specified properties. 
    Session session = Session.getDefaultInstance(props);

    // Create a message with the specified information. 
    MimeMessage msg = new MimeMessage(session);
    msg.setReplyTo(InternetAddress.parse("no-reply@no-host.com"));
    msg.setFrom(new InternetAddress(FROM));
    msg.setRecipient(Message.RecipientType.TO, new InternetAddress(TO));
    msg.setSubject(SUBJECT);
    msg.setContent(BODY, "html/plain");

    // Create a transport.        
    Transport transport = session.getTransport("smtp");

    // Send the message.
    try {
        System.out.println("Attempting to send an email through the Amazon SES SMTP interface...");

        // Connect to Amazon SES using the SMTP username and password you specified above.
        transport.connect(HOST, PORT, SMTP_USERNAME, SMTP_PASSWORD);

        // Send the email.
        transport.sendMessage(msg, msg.getAllRecipients());
        System.out.println("Email sent!");
    } catch (Exception ex) {
        System.out.println("The email was not sent.");
        System.out.println("Error message: " + ex.getMessage());
    } finally {
        // Close and terminate the connection.
        transport.close();
    }
}

这是来自 Windows 环境的 java 邮件日志(正在运行的环境):

DEBUG: JavaMail version 1.5.4
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
Attempting to send an email through the Amazon SES SMTP interface...
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "email-smtp.us-west-2.amazonaws.com", port 25, isSSL false
220 email-smtp.amazonaws.com ESMTP SimpleEmailService-1207632523 H3nxFSQJ7ktEpHBHuT38
DEBUG SMTP: connected to host "email-smtp.us-west-2.amazonaws.com", port: 25

EHLO roberton
250-email-smtp.amazonaws.com
250-8BITMIME
250-SIZE 10485760
250-STARTTLS
250-AUTH PLAIN LOGIN
250 Ok
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "SIZE", arg "10485760"
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "AUTH", arg "PLAIN LOGIN"
DEBUG SMTP: Found extension "Ok", arg ""
STARTTLS
220 Ready to start TLS
EHLO xxxxxxxxxxxxxxxx
250-email-smtp.amazonaws.com
250-8BITMIME
250-SIZE 10485760
250-STARTTLS
250-AUTH PLAIN LOGIN
250 Ok
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "SIZE", arg "10485760"
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "AUTH", arg "PLAIN LOGIN"
DEBUG SMTP: Found extension "Ok", arg ""
DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM 
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN succeeded
DEBUG SMTP: use8bit false
MAIL FROM:<naoresponder@xxxxxxxxx>
250 Ok
RCPT TO:<xxxxxxxxxxxxxxxxxxxxx>
250 Ok
DEBUG SMTP: Verified Addresses
DEBUG SMTP:   xxxxxxxxxxxxxxx
DATA
354 End data with <CR><LF>.<CR><LF>
From: xxxxxxxxxxxxxx
Reply-To: xxxxxxxxxxxxx
To: xxxxxxxxxxxxxxxxxxx
Message-ID: <1926764753.0.1448359358140@xxxxxxxx>
Subject: Amazon SES test (SMTP interface accessed using Java)
MIME-Version: 1.0
Content-Type: html/plain
Content-Transfer-Encoding: 7bit

This email was sent through the Amazon SES SMTP interface by using Java.
.
250 Ok 0000015138f203b5-6fcd5424-60c3-43eb-9542-83699cf36c46-000000
DEBUG SMTP: message successfully delivered to mail server
Email sent!
QUIT
221 Bye

这是来自 Ubuntu 的日志(环境不工作):

DEBUG: JavaMail version 1.5.4
DEBUG: successfully loaded resource: /META-INF/javamail.default.providers
DEBUG: Tables of loaded providers
DEBUG: Providers Listed By Class Name: {com.sun.mail.smtp.SMTPSSLTransport=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], com.sun.mail.smtp.SMTPTransport=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle], com.sun.mail.imap.IMAPSSLStore=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], com.sun.mail.pop3.POP3SSLStore=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], com.sun.mail.imap.IMAPStore=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], com.sun.mail.pop3.POP3Store=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle]}
DEBUG: Providers Listed By Protocol: {imaps=javax.mail.Provider[STORE,imaps,com.sun.mail.imap.IMAPSSLStore,Oracle], imap=javax.mail.Provider[STORE,imap,com.sun.mail.imap.IMAPStore,Oracle], smtps=javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle], pop3=javax.mail.Provider[STORE,pop3,com.sun.mail.pop3.POP3Store,Oracle], pop3s=javax.mail.Provider[STORE,pop3s,com.sun.mail.pop3.POP3SSLStore,Oracle], smtp=javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]}
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
Attempting to send an email through the Amazon SES SMTP interface...
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "email-smtp.us-west-2.amazonaws.com", port 25, isSSL false
220 email-smtp.amazonaws.com ESMTP SimpleEmailService-1207632523 tIUsmWGoY4gXLCMWdUpi
DEBUG SMTP: connected to host "email-smtp.us-west-2.amazonaws.com", port: 25

EHLO xxxxxxxxx
250-email-smtp.amazonaws.com
250-8BITMIME
250-SIZE 10485760
250-AUTH PLAIN LOGIN
250 Ok
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "SIZE", arg "10485760"
DEBUG SMTP: Found extension "AUTH", arg "PLAIN LOGIN"
DEBUG SMTP: Found extension "Ok", arg ""
DEBUG SMTP: STARTTLS required but not supported
The email was not sent.
Error message: STARTTLS is required but host does not support STARTTLS

这是调用堆栈错误:

javax.mail.MessagingException: STARTTLS is required but host does not support STARTTLS
        at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:719)
        at javax.mail.Service.connect(Service.java:364)
        at SESEmail.main(SESEmail.java:64)

Java版本:1.8.0_60-b27

为什么会这样?

我使用的是来自 AWS SES http://docs.aws.amazon.com/ses/latest/DeveloperGuide/send-using-smtp-java.html 的官方示例,而这个示例使用的是用于 TLS 的端口 smtp 25。

出于某种原因,此端口 (25) 在我的某些环境中不适用于 TLS。

经过一些研究,我发现了这个 http://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-connect.html 并尝试使用默认的 TLS 端口 587,现在它在我的两个环境(linux 和 windows)中都有效。

我认为这是来自 AWS SES 服务器的 problem/behavior 而不是 Java 邮件问题。我会尝试向 AWS 团队报告此事。