使用 JavaMail API 时出现 SSLException

Posted

技术标签:

【中文标题】使用 JavaMail API 时出现 SSLException【英文标题】:SSLException in using JavaMail API 【发布时间】:2012-08-11 09:51:42 【问题描述】:

我正在使用 Java Mail API 来开发一个发送邮件的应用程序。如果我使用 yahoo 或 gmail 托管的邮件服务器,我可以成功发送邮件。但是,当我尝试使用自己的邮件服务器时,我无法发送邮件,可能导致失败的原因是什么?当我在我的设备中执行我的应用程序时,它显示“电子邮件未发送”,因此不会发生异常。请问我该如何更改我的程序,以便我可以成功地将我的应用程序连接到我的 smtp 服务器,或者我如何才能获得更多信息来显示以便我可以理解连接失败的原因。

这是我的程序: 发件人.java

public class Sender extends Activity 

    Button Send;
    TextView text;

    @Override
    public void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sender);

        Send = (Button) findViewById(R.id.mail);
        text = (TextView) findViewById(R.id.textView1);

        StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
        .permitAll().build();
        StrictMode.setThreadPolicy(policy); 

        Send.setOnClickListener(new View.OnClickListener() 

            @Override
            public void onClick(View v) 
                // TODO Auto-generated method stub
                new SendMail().execute();
            
        );

    

    private class SendMail extends AsyncTask<String, Void, Integer> 
     
        ProgressDialog pd = null;
        String error = null;
        Integer result;

        @Override 
        protected void onPreExecute()  
            // TODO Auto-generated method stub 
            super.onPreExecute(); 
            pd = new ProgressDialog(Sender.this); 
            pd.setTitle("Sending Mail"); 
            pd.setMessage("Please wait..."); 
            pd.setCancelable(false); 
            pd.show(); 
         

        @Override  
        protected Integer doInBackground(String... params)   
            // TODO Auto-generated method stub  

            MailSender sender = new MailSender("me@mysmtp.com", "password");  

            sender.setTo(new String[]"you@mysmtp.com", "me@gmail.com"); 
            sender.setFrom("me@mysmtp.com"); 
            sender.setSubject("Test mail"); 
            sender.setBody("This is the mail body"); 
            try  
                if(sender.send())  
                    System.out.println("Message sent"); 
                    return 1; 
                 else 
                    return 2; 
                 
             catch (Exception e)     
             error = e.getMessage(); 
             Log.e("SendMail", e.getMessage(), e);     
             
            return 3;  
          

        protected void onPostExecute(Integer result)  
            pd.dismiss(); 
            if(error!=null)  
                text.setText(error); 
             
            if(result==1)  
                Toast.makeText(Sender.this, 
                    "Email was sent successfully.", Toast.LENGTH_LONG) 
                    .show(); 
             else if(result==2)  
                Toast.makeText(Sender.this, 
                    "Email was not sent.", Toast.LENGTH_LONG).show(); 
             else if(result==3)  
                Toast.makeText(Sender.this, 
                    "There was a problem sending the email.", 
                    Toast.LENGTH_LONG).show(); 
             
         
      

MailSender.java

public class MailSender extends Authenticator  
    private String user; 
    private String password; 

    private String [] to; 
    private String from; 

    private String port; 
    private String sport; 

    private String host; 

    private String subject; 
    private String body; 

    private boolean auth; 
    private boolean debuggable; 

    private Multipart multi; 

    public MailSender() 
        host = "web.mysmtp.com"; 
        port = "25"; 
        sport = "25"; 

        user = ""; 
        password = ""; 
        from = ""; 
        subject = ""; 
        body = ""; 

        debuggable = false; 
        auth = true; 

        multi = new MimeMultipart(); 

        // There is something wrong with MailCap, javamail can not find a handler for the multipart/mixed part, so this bit needs to be added. 
        MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();  
        mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");  
        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);  
     

    public MailSender(String user, String password) 
        this();       
        this.user = user; 
        this.password = password;    
     

    public boolean send() throws Exception  
        Properties props = setProperties(); 

        try 
            Session session = Session.getInstance(props, this); 
            session.setDebug(true); 

            MimeMessage msg = new MimeMessage(session); 

            msg.setFrom(new InternetAddress(from)); 

            InternetAddress[] addressTo = new InternetAddress[to.length]; 
            for(int i=0; i<to.length; i++) 
                addressTo[i] = new InternetAddress(to[i]); 
             

            msg.setRecipients(MimeMessage.RecipientType.TO, addressTo); 
            msg.setSubject(subject); 
            msg.setSentDate(new Date()); 

            BodyPart messageBodyPart = new MimeBodyPart(); 
            messageBodyPart.setText(body); 
            multi.addBodyPart(messageBodyPart); 

            msg.setContent(multi); 

            Transport transport = session.getTransport("smtps"); 
            transport.connect(host, 25, user, password); 
            transport.sendMessage(msg, msg.getAllRecipients()); 
            transport.close(); 
            return true; 
         catch (Exception e)  
            e.printStackTrace(); 
            return false; 
         
     

    public void addAttachment(String filename) throws Exception  
        BodyPart messageBodyPart = new MimeBodyPart(); 
        DataSource source = new FileDataSource(filename); 
        messageBodyPart.setDataHandler(new DataHandler(source)); 
        messageBodyPart.setFileName(filename); 

        multi.addBodyPart(messageBodyPart); 
     

    @Override  
      public PasswordAuthentication getPasswordAuthentication()   
        return new PasswordAuthentication(user, password);  
       

    private Properties setProperties()  
        Properties props = new Properties(); 

        props.put("mail.smtp.host", host); 

        if(debuggable)  
            props.put("mail.debug", "true"); 
         

        if(auth)  
            props.put("mail.smtp.auth", "true"); 
         

        props.put("mail.smtp.port", port); 
        props.put("mail.smtp.socketFactory.port", sport); 
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); 
        props.put("mail.smtp.socketFactory.fallback", "false"); 

        return props; 
     

    public void setTo(String[] toAddress)  
        this.to = toAddress; 
     

    public void setFrom(String fromAddress)  
        this.from = fromAddress; 
     

    public void setSubject(String subject)  
        this.subject = subject; 
     

    public void setBody(String body)   
        this.body = body;  
     

错误日志中的错误消息:

08-15 11:21:37.284: W/System.err(2553):     javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x5c075548: Failure in SSL library, usually a protocol error
08-15 11:21:37.291: W/System.err(2553): Caused by: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x5c075548: Failure in SSL library, usually a protocol error
08-15 11:21:37.299: W/System.err(2553): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x5c075548: Failure in SSL library, usually a protocol error

【问题讨论】:

【参考方案1】:

您正在连接到端口 25 并使用 SSL。端口 25 是非 SSL(纯文本)端口。假设您的服务器设置为 SSL,请使用不需要您指定端口号的连接方法,并让 JavaMail 使用默认端口。

【讨论】:

那么我需要做的是去掉端口的规范,所以隐藏下面三行? props.put("mail.smtp.port", 端口); props.put("mail.smtp.socketFactory.port", 运动); props.put("mail.smtp.socketFactory.class", "javax.net.SocketFactory"); 是的,你根本不需要套接字工厂属性,并且端口属性被忽略了,因为你调用了这个方法:transport.connect(host, 25, user, password);将其替换为 transport.connect(host, user, password);【参考方案2】:

您的 SMTP 服务器的 SSL 配置将是我要检查的第一件事。如果您的类与外部服务一起使用,那么它就是您的服务器的安全配置。

【讨论】:

所以你的意思是我应该在 "props.put("mail.smtp.socketFactory.class", "javax.net. ssl.SSLSocketFactory");"?是不是还需要改,因为改了之后还是发不出去。【参考方案3】:

您可能会收到该错误,因为您没有在服务器端创建签名证书。如果您确实设置了 SSL 验证,则说明您没有正确设置,或者您连接的服务器的证书尚未添加到信任库中。

这篇文章 (How Can I Access an SSL Connection Through android?) 提供了一个关于如何初始化密钥库和信任库的代码示例的答案。

【讨论】:

【参考方案4】:

Java Mail API 会导致很多问题,here 是我最近使用几个不同的邮件服务器测试的各种 pop3/smtp 连接的工作示例。

【讨论】:

以上是关于使用 JavaMail API 时出现 SSLException的主要内容,如果未能解决你的问题,请参考以下文章

Java Mail:在没有 SSL 的端口 25 上发送电子邮件时出现 SSLHandshakeException

为啥调用 API 时出现 CORS 错误

使用参数获取方法时出现野狗错误

使用 facebook api 时出现错误

尝试使用 twilio Api phpSDK 发送消息时出现致命错误

错误:使用天气 API 时出现 XMLHttpRequest 错误