一个邮件程序搞了一个月

一次微软Exchange被坑的经历

Posted by 就是我啦 on June 1, 2022

一个邮件程序搞了一个月

最普通不过的Email发送程序,居然搞了一个月。

猜中了开头,缺猜不中这结尾。。。

# 用了微软的软件,就要小心些

发生了什么

最近的项目,甲方要求能提供发送邮件的功能,问甲方要Email Server的配置,甲方说就是一般的,没啥特殊。也就没当回事,项目小伙子就调用了常见的Hutool包写好了email程序,并用自己的QQ邮箱做了测试,完美。

结果,在客户环境中测试缺发现了问题,死活都不通

和甲方确认,email server是不是有特殊的设置,甲方就一句话:“没啥特殊的,我们其他系统都能连的上”。要求对方提供示例代码,对方却说没有java的,只有C#的。总之,给不了什么有用的信息。

恶心的是,远程开发还连不上客户的机器,测试都要打个jar包,发给客户,申请给考过去,然后再测,这样搞一次就得一天。

真是甲方虐我千百遍,我待甲方。。。

怎么办

原来能看到的软件报错信息很少,先想办法把错误信息列详细点吧。

后来,打开了Hutool email的debug模式,终于看到了报错信息:

DEBUG: JavaMail version 1.4.7
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]
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: useEhlo true, useAuth true
DEBUG SMTP: trying to connect to host "10.10.20.34", port 25, isSSL false
220 CSE-EX01.CSE.COM.CN Microsoft ESMTP MAIL Service ready at Wed, 25 May 2022 10:49:07 +0800
DEBUG SMTP: connected to host "10.10.20.34", port: 25

EHLO localhost
250-CSE-EX01.CSE.COM.CN Hello [10.10.22.58]
250-SIZE 37748736
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-STARTTLS
250-X-ANONYMOUSTLS
250-AUTH NTLM
250-X-EXPS GSSAPI NTLM
250-8BITMIME
250-BINARYMIME
250-CHUNKING
250-SMTPUTF8
250 XRDST
DEBUG SMTP: Found extension "SIZE", arg "37748736"
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "DSN", arg ""
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "STARTTLS", arg ""
DEBUG SMTP: Found extension "X-ANONYMOUSTLS", arg ""
DEBUG SMTP: Found extension "AUTH", arg "NTLM"
DEBUG SMTP: Found extension "X-EXPS", arg "GSSAPI NTLM"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "BINARYMIME", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "SMTPUTF8", arg ""
DEBUG SMTP: Found extension "XRDST", arg ""
DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM
DEBUG SMTP: mechanism LOGIN not supported by server
DEBUG SMTP: mechanism PLAIN not supported by server
DEBUG SMTP: mechanism DIGEST-MD5 not supported by server
DEBUG NTLM: type 1 message: 4E 54 4C 4D 53 53 50 00 01 00 00 00 03 A2 00 00 00 00 00 00 29 00 00 00 09 00 09 00 20 00 00 00 6C 6F 63 61 6C 68 6F 73 74
DEBUG SMTP: AUTH NTLM command trace suppressed
DEBUG NTLM: type 3 message: 4E 54 4C 4D 53 53 50 00 03 00 00 00 18 00 18 00 78 00 00 00 18 00 18 00 90 00 00 00 00 00 00 00 40 00 00 00 26 00 26 00 40 00 00 00 12 00 12 00 66 00 00 00 00 00 00 00 A8 00 00 00 01 82 00 00 6E 00 63 00 72 00 61 00 64 00 6D 00 69 00 6E 00 40 00 63 00 73 00 65 00 2E 00 63 00 6F 00 6D 00 2E 00 63 00 6E 006C 00 6F 00 63 00 61 00 6C 00 68 00 6F 00 73 00 74 00 20 58 47 04 EB 40 4B C4 A8 0F 0C B3 11 23 AE D8 D5 E5 23 BD CC B3 AE DE 49 47 93 AF 55 3D 47 98 3E A7 44 18 0F 2E 1B 08 DE 8C 4E 49 6F A4 1D 7B
DEBUG SMTP: AUTH NTLM failed
Exception in thread "main" cn.hutool.extra.mail.MailException: AuthenticationFailedException: 535 5.7.3 Authentication unsuccessful

        at cn.hutool.extra.mail.Mail.send(Mail.java:229)
        at com.hzwindpower.common.util.EmailUtil.send(EmailUtil.java:213)
        at com.hzwindpower.common.util.EmailUtil.main(EmailUtil.java:146)
Caused by: javax.mail.AuthenticationFailedException: 535 5.7.3 Authentication unsuccessful

看到了很醒目的“AUTH NTLM failed”,这是Windows的东西!

windows域有关系!

问题是客户连域名都没告诉过我们!

问客户要来域名,又经过来来回回N多次测试,终于在快一个月的时候解决了。。。

最后解决

最后证明Hutool不行,只能用微软Exchange自己的包

详细可以参照这里

<dependency>
            <groupId>com.microsoft.ews-java-api</groupId>
            <artifactId>ews-java-api</artifactId>
            <version>2.0</version>
</dependency>

而且走的也不是smtp的标准服务,而是Exchange自己的什么EWS服务。

看下面这段代码,应该是https的web 服务。

  /**
     * @Desc 发送邮件
     * @return
     */
    public Map<String, Object> sendExchange() {
        Map<String, Object> map=new HashMap<>();
        // Exchange服务器版本。
        ExchangeService exchangeService = new ExchangeService(exchangeVersion);

        // 要在MS Exchange服务器上签名的凭据。
        ExchangeCredentials exchangeCredentials = new WebCredentials(username, password, domain);
        exchangeService.setCredentials(exchangeCredentials);

        // 邮箱的exchange web服务的URL
        try {
            exchangeService.setUrl(new URI("https://" + hostname + "/ews/Exchange.asmx"));
        } catch (URISyntaxException ex) {
            logger.error("创建与服务端的连接发生异常", ex);
            if(exchangeService!=null) {
                exchangeService.close();
            }
            map.put("error","创建与服务端的连接发生异常");
            return map;
        }

        // 设置邮件信息
        EmailMessage emailMessage;
        try {
            emailMessage = new EmailMessage(exchangeService);
            emailMessage.setSubject(subject);
            emailMessage.setBody(MessageBody.getMessageBodyFromText(message));
        } catch (Exception ex) {
            logger.error("设置邮件发生异常", ex);
            map.put("error","设置邮件发生异常");
            return map;
        }

        // 设置收件人
        for (String temp : recipientToList) {
            try {
                emailMessage.getToRecipients().add(temp);
            } catch (ServiceLocalException ex) {
                logger.error("设置邮件收件人发生异常.", ex);
                map.put("error", "设置邮件收件人发生异常");
                return map;
            }
        }

另外,还要注意,就是用户名有的时候要domain\username的形式,有的时候又不需要domain,直接username就可以。。

总结

  1. 碰到微软的东西还是要小心点
  2. 国内的软件国产自主可控转换的趋势已经不可逆转,大快人心!