Java SMTP SSL 发送邮件 Received fatal alert

引言

在开发过程中,我们经常会遇到需要通过代码发送电子邮件的需求。在使用 Java 发送邮件时,通常会使用 SMTP(Simple Mail Transfer Protocol)协议来完成邮件的发送。而在某些情况下,我们还需要使用 SSL(Secure Sockets Layer)来保证邮件的安全传输。然而,有时会遇到 "Received fatal alert" 错误,本文将解释该错误的原因,并提供解决方案。

SMTP 和 SSL

SMTP 是一种用于发送电子邮件的协议。它定义了邮件的传输规则和通信方式。SMTP 协议通常使用 25 号端口进行传输。然而,为了保护邮件的隐私和安全性,我们可能需要使用 SSL 加密来对 SMTP 连接进行安全加固。

SSL 是一种加密协议,用于保护网络通信的安全性。它使用公钥和私钥的组合来对通信进行加密和解密。SSL 通常使用 465 号端口进行传输。

Received fatal alert 错误

当我们在 Java 中使用 SMTP SSL 发送邮件时,有时会遇到 "Received fatal alert" 错误。该错误通常表示 SSL 连接遇到了严重的问题,无法继续进行。

错误示例

以下是一个典型的错误示例:

import java.util.Properties;
import javax.mail.*;
import javax.mail.internet.*;

public class SendEmail {
    public static void main(String[] args) {
        String to = "receiver@example.com";
        String from = "sender@example.com";
        String host = "smtp.example.com";

        Properties properties = System.getProperties();
        properties.setProperty("mail.smtp.host", host);
        properties.setProperty("mail.smtp.port", "465");
        properties.setProperty("mail.smtp.ssl.enable", "true");

        Session session = Session.getDefaultInstance(properties);

        try {
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(from));
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
            message.setSubject("Test Subject");
            message.setText("Test Body");

            Transport.send(message);
            System.out.println("Message sent successfully");
        } catch (MessagingException mex) {
            mex.printStackTrace();
        }
    }
}

当运行上述代码时,我们可能会遇到以下错误:

javax.mail.MessagingException: Could not connect to SMTP host: smtp.example.com, port: 465, response: -1
    at com.sun.mail.smtp.SMTPTransport.openServer(SMTPTransport.java:2209)
    at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:740)
    at javax.mail.Service.connect(Service.java:366)
    at javax.mail.Service.connect(Service.java:246)
    at javax.mail.Service.connect(Service.java:267)
    at javax.mail.Transport.send0(Transport.java:252)
    at javax.mail.Transport.send(Transport.java:174)
    at SendEmail.main(SendEmail.java:29)

这个错误说明了无法连接到 SMTP 服务器,可能是由于 SSL 连接问题导致的。

解决方案

为了解决 "Received fatal alert" 错误,我们需要进行以下几个步骤:

1. 导入证书

首先,我们需要将 SMTP 服务器的证书导入到 Java Keystore 中。可以使用以下命令来完成导入:

keytool -import -alias smtp -keystore cacerts -file smtp.crt

这里,smtp.crt 是 SMTP 服务器的证书文件,cacerts 是 Java Keystore 文件,默认路径为 $JAVA_HOME/lib/security/cacerts

2. 设置信任策略

接下来,我们需要设置信任策略。在代码中,我们可以使用 TrustAllManager 类来实现信任所有证书的策略:

import javax.net.ssl.*;

public class TrustAllManager implements X509TrustManager {
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }

    public void checkClientTrusted(X509Certificate[] certs, String authType) {
    }

    public void checkServerTrusted(X509Certificate[] certs, String authType) {
    }
}

然后,在代码的 main 方法中,我们需要添加以下代码来设置信任策略:

// 设置信任策略
TrustManager[] trustAllCerts = new TrustManager[] { new TrustAllManager() };
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts,