1. 程式人生 > >一個使用smtp傳送郵件的問題

一個使用smtp傳送郵件的問題

使用smtp.163.com傳送郵件,參考:https://www.cnblogs.com/tohxyblog/p/6593654.html

登入郵箱做好設定之後,程式碼如下:

    @Test
    public void testSendEmail() throws Exception {

        Properties prop = new Properties();
        prop.setProperty("mail.transport.protocol", "smtp"); //協議
        prop.setProperty("mail.smtp.host", "smtp.163.com"); //主機名smtp.163.com
        prop.setProperty("mail.smtp.auth", "true"); //是否開啟許可權控制
        prop.setProperty("mail.debug", "true"); //返回傳送的cmd原始碼
        Session session = Session.getInstance(prop);

        Message msg = new MimeMessage(session);
        msg.setFrom(new InternetAddress("[email protected]")); //自己的email
        msg.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress("[email protected]")); // 要傳送的email,可以設定陣列
        msg.setSubject("裝修問題諮詢");  //郵件標題
        msg.setText("請問你們裝修一次多少錢");//郵件正文
        //不被當作垃圾郵件的關鍵程式碼--Begin ,如果不加這些程式碼,傳送的郵件會自動進入對方的垃圾郵件列表
        msg.addHeader("X-Priority", "3");
        msg.addHeader("X-MSMail-Priority", "Normal");
        msg.addHeader("X-Mailer", "Microsoft Outlook Express 6.00.2900.2869"); //本文以outlook名義傳送郵件,不會被當作垃圾郵件
        msg.addHeader("X-MimeOLE", "Produced By Microsoft MimeOLE V6.00.2900.2869");
        msg.addHeader("ReturnReceipt", "1");
        //不被當作垃圾郵件的關鍵程式碼--end
        Transport trans = session.getTransport();

        //密碼不是郵箱登入密碼,是客戶端授權密碼
        trans.connect("[email protected]", "******"); // 郵件的賬號密碼
        trans.sendMessage(msg, msg.getAllRecipients());

    }

這段邏輯在本地執行只要內容沒有被163伺服器退信,就沒有問題。但在阿里雲伺服器上,不管是杭州的還是香港的,都會有連線超時的問題,由於在阿里雲伺服器上部署了nginx,前端會返回一個504錯誤。檢視nginx的log(/usr/local/nginx/logs/error.log)發現有:

2019/05/14 16:06:46 [error] 16039#0: *137116 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 60.176.118.119, server: localhost, request: "POST /zk/alarmConfig/sendEmail?emial=undefined HTTP/1.1", upstream: "http://127.0.0.1:9999/alarmConfig/sendEmail?emial=undefined", host: "esl.zkong.com:8888", referrer: "http://esl.zkong.com:8888/"
 

歸根到底還是由於方法本身的呼叫超時,排除nginx的問題。搜了一下“阿里雲 smtp”發現阿里雲的伺服器將向外訪問25的埠封了,需要使用465埠和ssl通訊,參考:https://blog.csdn.net/liouxl0623/article/details/65446662

使用程式碼:

    @Test
    public void testSslSend() {
        try{
            AgencyAlarmConfig agencyAlarmConfig = new AgencyAlarmConfig();
            agencyAlarmConfig.setAccount("[email protected]");
            agencyAlarmConfig.setPassword("******");
            agencyAlarmConfig.setSendServer("smtp.163.com");
            agencyAlarmConfig.setTestMail("[email protected]");
            agencyAlarmConfig.setMailTitle("真不巧");
            Assert.assertTrue(sslSend(agencyAlarmConfig, "嘿嘿"));
        } catch (Exception e) {
            Assert.fail();
        }
    }


    private boolean sslSend(AgencyAlarmConfig agencyAlarmConfig, String content)
            throws AddressException, MessagingException, IOException {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
        // Get a Properties object
        Properties props = new Properties();
        props.setProperty("mail.smtp.host", agencyAlarmConfig.getSendServer());
        props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
        props.setProperty("mail.smtp.socketFactory.fallback", "false");
        props.setProperty("mail.smtp.port", "465");
        props.setProperty("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.auth", "true");

        final String username = agencyAlarmConfig.getAccount();
        final String password = agencyAlarmConfig.getPassword();
        Session session = Session.getDefaultInstance(props, new Authenticator(){
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }});
        Message msg = new MimeMessage(session);

        // 設定發件人和收件人
        msg.setFrom(new InternetAddress(agencyAlarmConfig.getAccount()));
        List<String> tos = new ArrayList<>();
        tos.add(agencyAlarmConfig.getTestMail());
        Address to[] = new InternetAddress[tos.size()];
        for(int i=0;i<tos.size();i++){
            to[i] = new InternetAddress(tos.get(i));
        }
        // 多個收件人地址
        msg.setRecipients(Message.RecipientType.TO, to);
        msg.setSubject(agencyAlarmConfig.getMailTitle()); // 標題
        msg.setText(content);// 內容
        msg.setSentDate(new Date());
        Transport.send(msg);
        System.out.println("EmailUtil ssl協議郵件傳送列印" +msg.toString());
        return true;
    }

由此可在阿里雲的香港,杭州伺服器傳送,對於封埠,阿里雲的迴應:

去年9月底開始,出於上級對垃圾郵件管控的要求,新購VPC伺服器限制了25埠,我們建議您使用郵件服務商的加密465埠。 或者您查詢下所希望訪問的發信服務是否提供了像阿里雲企業郵箱一樣的重定向25埠,這樣不用解封25埠也可以發信。阿里雲企業郵箱將80埠重定向到了25端,與直接呼叫25端的發信方式沒有區別。 如果您僅用於本地發信,可嘗試使用阿里企郵 smtp 80 埠。smtp.mxhichina.com 80