【问题标题】:How to send an email using MS exchange server如何使用 MS Exchange 服务器发送电子邮件
【发布时间】:2020-10-21 01:35:36
【问题描述】:

我正在尝试使用我公司的邮件服务器发送电子邮件。但我得到以下异常

Caused by: com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.1 Client was not authenticated
    at com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:1388)
    at com.sun.mail.smtp.SMTPTransport.mailFrom(SMTPTransport.java:959)
    at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:583)
    at javax.mail.Transport.send0(Transport.java:169)
    at javax.mail.Transport.send(Transport.java:98)

这是我的示例代码,

Properties props = System.getProperties();

// Setup mail server
props.put("mail.smtp.host", "example.server.com");
props.put("mail.smtp.auth", "true");
props.put("mail.debug", "true");
props.put("mail.smtp.port", "25");
// Get session
//Session session = Session.getDefaultInstance(props, null);
Session session = Session.getDefaultInstance(props,
    new javax.mail.Authenticator() {
        protected PasswordAuthentication getPasswordAuthentication() {
            return new PasswordAuthentication("username", "password");
        }
    });

// Define message
MimeMessage message = new MimeMessage(session);

// Set the from address
message.setFrom(new InternetAddress(from));

// Set the to address
message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

// Set the subject
message.setSubject("Hello JavaMail");

// Set the content
message.setText("Welcome to JavaMail");

// Send message
Transport.send(message);

哪段代码错了? 至于用户名和密码,我使用的是我公司的电子邮件地址和密码。

【问题讨论】:

    标签: java jakarta-mail


    【解决方案1】:

    5.7.1 可能是交换造成的,而不是你的代码。您可能只需要在服务器上启用中继。对于匿名用户或来自某个 IP 地址的用户。我不是 Exchange 方面的专家,但我以前有过这个工作。这是我测试过的最后一个可行的解决方案:

    如果在用户已通过身份验证后尝试通过 Exchange 服务器上的 SMTP 发送电子邮件时遇到 5.7.1 错误..

    对于 ref,您刚刚遇到的问题是由 Exchange 2007 服务器上的设置引起的 - 这通常不会是 2003 服务器上的问题

    通过以下操作修复...

    您可以通过 GUI 设置此身份验证设置

    • 在服务器配置/集线器传输/默认
    • 右键单击、属性、权限组
    • 勾选“匿名用户”,然后点击确定

    显然匿名用户不太安全,但您可以看看这是否解决了问题。

    【讨论】:

    • 我的 IT 管理员是否可以在 Exchange 服务器上创建一个测试用户并用于发送电子邮件?
    • 我不明白为什么不这样做。我的网络应用程序在模拟域用户下运行,该域用户连接到交换服务器。我不太了解交换,但安装应用程序的最后一个站点必须允许通过 smtp 从 Web 服务器进行中继。在此之后我停止收到 5.7.1 错误。如果你不能做一个用户,那么你至少应该能够做一个机器。这里有一些关于单个用户无法中继的问题的信息,其中有一些有趣的信息social.technet.microsoft.com/Forums/en-US/exchangesvrtransport/…
    • 我认为您需要寻找的区域是“接收连接器”
    • 感谢 WraithNath 的宝贵意见。我将使用一位测试用户发送所有电子邮件。但我也通过在 gmail 上创建一个用户并使用该用户发送消息来测试我的应用程序,并且工作正常。但我的最终目标是使用公司的邮件服务器。您的帮助给了我非常宝贵的意见。
    【解决方案2】:

    当我将使用 MS Exhange SMTP 服务器发送电子邮件时,我使用上述 maven 依赖项。

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

    出于这个原因,我创建了一个代表 MS Exchange 服务器的电子邮件客户端的类。我使用 log4j 进行日志记录。

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    

    在 MS Exchange 客户端类下面(我使用构建器模式来构造对象以确保线程安全),

    import java.net.URI;
    import java.net.URISyntaxException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    import microsoft.exchange.webservices.data.core.ExchangeService;
    import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
    import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException;
    import microsoft.exchange.webservices.data.core.service.item.EmailMessage;
    import microsoft.exchange.webservices.data.credential.ExchangeCredentials;
    import microsoft.exchange.webservices.data.credential.WebCredentials;
    import microsoft.exchange.webservices.data.property.complex.MessageBody;
    import org.apache.log4j.Logger;
    
    /**
     * A client to connect to a MS Exchange SMTP Server.
     */
    public final class ExchangeClient {
    
        private static final Logger LOGGER = Logger.getLogger(ExchangeClient.class);
    
        private final String hostname;
        private final ExchangeVersion exchangeVersion;
        private final String domain;
        private final String username;
        private final String password;
        private final String subject;
        private final String recipientTo;
        private final List<String> recipientCc;
        private final List<String> recipientBcc;
        private final List<String> attachments;
        private final String message;
    
        private ExchangeClient(ExchangeClientBuilder builder) {
            this.hostname = builder.hostname;
            this.exchangeVersion = builder.exchangeVersion;
            this.domain = builder.domain;
            this.username = builder.username;
            this.password = builder.password;
            this.subject = builder.subject;
            this.recipientTo = builder.recipientTo;
            this.recipientCc = builder.recipientCc;
            this.recipientBcc = builder.recipientBcc;
            this.attachments = builder.attachments;
            this.message = builder.message;
        }
    
        public static class ExchangeClientBuilder {
    
            private String hostname;
            private ExchangeVersion exchangeVersion;
            private String domain;
            private String username;
            private String password;
            private String subject;
            private String recipientTo;
            private List<String> recipientCc;
            private List<String> recipientBcc;
            private List<String> attachments;
            private String message;
    
            public ExchangeClientBuilder() {
                this.exchangeVersion = ExchangeVersion.Exchange2010_SP1;
                this.hostname = "";
                this.username = "";
                this.password = "";
                this.subject = "";
                this.recipientTo = "";
                this.recipientCc = new ArrayList<>(0);
                this.recipientBcc = new ArrayList<>(0);
                this.attachments = new ArrayList<>(0);
                this.message = "";
            }
    
            /**
             * The hostname of the Exchange Web Service. It will be used for
             * connecting with URI https://hostname/ews/exchange.asmx
             *
             * @param hostname the hostname of the MS Exchange Smtp Server.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder hostname(String hostname) {
                this.hostname = hostname;
                return this;
            }
    
            /**
             * The Exchange Web Server version.
             *
             * @param exchangeVersion the Exchange Web Server version.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder exchangeVersion(ExchangeVersion exchangeVersion) {
                this.exchangeVersion = exchangeVersion;
                return this;
            }
    
            /**
             * The domain of the MS Exchange Smtp Server.
             *
             * @param domain the domain of the Active Directory. The first part of
             * the username. For example: MYDOMAIN\\username, set the MYDOMAIN.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder domain(String domain) {
                this.domain = domain;
                return this;
            }
    
            /**
             * The username of the MS Exchange Smtp Server. The second part of the
             * username. For example: MYDOMAIN\\username, set the username.
             *
             * @param username the username of the MS Exchange Smtp Server.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder username(String username) {
                this.username = username;
                return this;
            }
    
            /**
             * The password of the MS Exchange Smtp Server.
             *
             * @param password the password of the MS Exchange Smtp Server.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder password(String password) {
                this.password = password;
                return this;
            }
    
            /**
             * The subject for this send.
             *
             * @param subject the subject for this send.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder subject(String subject) {
                this.subject = subject;
                return this;
            }
    
            /**
             * The recipient for this send.
             *
             * @param recipientTo the recipient for this send.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder recipientTo(String recipientTo) {
                this.recipientTo = recipientTo;
                return this;
            }
    
            /**
             * You can specify one or more email address that will be used as cc
             * recipients.
             *
             * @param recipientCc the first cc email address.
             * @param recipientsCc the other cc email address for this send.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder recipientCc(String recipientCc, String... recipientsCc) {
                // Prepare the list.
                List<String> recipients = new ArrayList<>(1 + recipientsCc.length);
                recipients.add(recipientCc);
                recipients.addAll(Arrays.asList(recipientsCc));
                // Set the list.
                this.recipientCc = recipients;
                return this;
            }
    
            /**
             * You can specify a list with email addresses that will be used as cc
             * for this email send.
             *
             * @param recipientCc the list with email addresses that will be used as
             * cc for this email send.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder recipientCc(List<String> recipientCc) {
                this.recipientCc = recipientCc;
                return this;
            }
    
            /**
             * You can specify one or more email address that will be used as bcc
             * recipients.
             *
             * @param recipientBcc the first bcc email address.
             * @param recipientsBcc the other bcc email address for this send.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder recipientBcc(String recipientBcc, String... recipientsBcc) {
                // Prepare the list.
                List<String> recipients = new ArrayList<>(1 + recipientsBcc.length);
                recipients.add(recipientBcc);
                recipients.addAll(Arrays.asList(recipientsBcc));
                // Set the list.
                this.recipientBcc = recipients;
                return this;
            }
    
            /**
             * You can specify a list with email addresses that will be used as bcc
             * for this email send.
             *
             * @param recipientBcc the list with email addresses that will be used
             * as bcc for this email send.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder recipientBcc(List<String> recipientBcc) {
                this.recipientBcc = recipientBcc;
                return this;
            }
    
            /**
             * You can specify one or more email address that will be used as cc
             * recipients.
             *
             * @param attachment the first attachment.
             * @param attachments the other attachments for this send.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder attachments(String attachment, String... attachments) {
                // Prepare the list.
                List<String> attachmentsToUse = new ArrayList<>(1 + attachments.length);
                attachmentsToUse.add(attachment);
                attachmentsToUse.addAll(Arrays.asList(attachments));
                // Set the list.
                this.attachments = attachmentsToUse;
                return this;
            }
    
            /**
             * You can specify a list with email attachments that will be used for
             * this email send.
             *
             * @param attachments the list with email attachments that will be used
             * for this email send.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder attachments(List<String> attachments) {
                this.attachments = attachments;
                return this;
            }
    
            /**
             * The body of the email message.
             *
             * @param message the body of the email message.
             * @return the builder for chain usage.
             */
            public ExchangeClientBuilder message(String message) {
                this.message = message;
                return this;
            }
    
            /**
             * Build a mail.
             *
             * @return an EmailApacheUtils object.
             */
            public ExchangeClient build() {
                return new ExchangeClient(this);
            }
        }
    
        public boolean sendExchange() {
            // The Exchange Server Version.
            ExchangeService exchangeService = new ExchangeService(exchangeVersion);
    
            // Credentials to sign in the MS Exchange Server.
            ExchangeCredentials exchangeCredentials = new WebCredentials(username, password, domain);
            exchangeService.setCredentials(exchangeCredentials);
    
            // URL of exchange web service for the mailbox.
            try {
                exchangeService.setUrl(new URI("https://" + hostname + "/ews/Exchange.asmx"));
            } catch (URISyntaxException ex) {
                LOGGER.error("An exception occured while creating the uri for exchange service.", ex);
                return false;
            }
    
            // The email.
            EmailMessage emailMessage;
            try {
                emailMessage = new EmailMessage(exchangeService);
                emailMessage.setSubject(subject);
                emailMessage.setBody(MessageBody.getMessageBodyFromText(message));
            } catch (Exception ex) {
                LOGGER.error("An exception occured while setting the email message.", ex);
                return false;
            }
    
            // TO recipient.
            try {
                emailMessage.getToRecipients().add(recipientTo);
            } catch (ServiceLocalException ex) {
                LOGGER.error("An exception occured while sstting the TO recipient(" + recipientTo + ").", ex);
                return false;
            }
    
            // CC recipient.
            for (String recipient : recipientCc) {
                try {
                    emailMessage.getCcRecipients().add(recipient);
                } catch (ServiceLocalException ex) {
                    LOGGER.error("An exception occured while sstting the CC recipient(" + recipient + ").", ex);
                    return false;
                }
            }
    
            // BCC recipient
            for (String recipient : recipientBcc) {
                try {
                    emailMessage.getBccRecipients().add(recipient);
                } catch (ServiceLocalException ex) {
                    LOGGER.error("An exception occured while sstting the BCC recipient(" + recipient + ").", ex);
                    return false;
                }
            }
    
            // Attachements.
            for (String attachmentPath : attachments) {
                try {
                    emailMessage.getAttachments().addFileAttachment(attachmentPath);
                } catch (ServiceLocalException ex) {
                    LOGGER.error("An exception occured while setting the attachment.", ex);
                    return false;
                }
            }
    
            try {
                emailMessage.send();
                LOGGER.debug("An email is send.");
            } catch (Exception ex) {
                LOGGER.error("An exception occured while sending an email.", ex);
                return false;
            }
    
            return true;
        }
    
    }
    

    一个工作示例,

    // import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
    ExchangeClient client = new ExchangeClient.ExchangeClientBuilder()
            .hostname("webmail.domainOfWeb.com")
            .exchangeVersion(ExchangeVersion.Exchange2010)
            .domain("ActiveDirectoryDomain")
            .username("ActiveDirectoryUsername")
            .password("ActiveDirectoryPassword")
            .recipientTo("recipient@whatever.com")
            .recipientCc("recipient@whatever.com") // Ignore it in case you will not use Cc recipients.
            .recipientBcc("recipient@whatever.com") // Ignore it in case you will not use Bcc recipients.
            .attachments("/home/username/image.png") // Ignore it in case you will not use attachements.
            .subject("Test Subject")
            .message("Test Message")
            .build();
    client.sendExchange();
    

    【讨论】:

    • 很好的解决方案!谢谢!
    • 我发现可能有用的一件事是,如果您想在发送前检查电子邮件,使用 emailMessage.save(); 而不是 emailMessage.end(); 会将电子邮件放入您的草稿 Outlook 文件夹中,可以发送到后期。
    【解决方案3】:

    Mail.jar(1.4.0 版)存在与 MS Exchange Server 的兼容性问题并抛出 530 5.7.1 Client was not authenticated,即使配置了用户名和密码也是如此。

    将邮件 API 升级到 1.4.4 或 1.4.7 应该可以解决问题。

    Mail API 的 1.4.7 可以从以下 URL 下载:http://www.oracle.com/technetwork/java/javamail/index.html

    【讨论】:

      【解决方案4】:

      在某些公司中,Exchange 服务器 SMTP 支持被禁用,您不能要求他们启用它。在这些情况下,一个合理的解决方案是:

      http://davmail.sourceforge.net/

      【讨论】:

        【解决方案5】:

        Simple Java Mail 为我工作。您唯一需要检查的是正确的 hostnameusernameportpassword TransportStrategy.SMTP_TLS:

        new Mailer(host, port, username, password, TransportStrategy.SMTP_TLS).sendMail(email);
        

        【讨论】:

        • @zeddam 是开源的吗?
        【解决方案6】:

        我不得不使用 javamail + exchange。返回的消息很无奈。 感谢堆栈,我得到了一些提示。

        将此添加到您的代码中

          props.put("mail.smtp.starttls.enable","true");
        

        考虑添加所用机器的证书。 要找到它们,只需转到您的浏览器,将它们导出并导入到正在使用的 cacerts 文件

        【讨论】:

          【解决方案7】:

          请使用以下代码部分代替Transport.send(message);

          MimeMessage message = new MimeMessage(session);
          
          message.saveChanges();
          Transport transport = session.getTransport("smtp");
          transport.connect(host, "user", "pwd");
          transport.sendMessage(message, message.getAllRecipients());
          transport.close();
          

          我已经在本地进行了测试,并且可以正常工作

          【讨论】:

          • Transport.send(message) 方法包括 message.saveChanges()transport.connecttransport.sendMessagetransport.close 所以我认为我不需要自己再做一次。
          【解决方案8】:

          ews-java-api 包的生命周期结束。

          来自https://github.com/OfficeDev/ews-java-api

          从 2018 年 7 月 19 日开始,Exchange Web 服务 (EWS) 将不再接收功能更新。虽然该服务将继续接收安全更新和某些非安全更新,但产品设计和功能将保持不变。此更改也适用于 Java 和 .NET 的 EWS SDK。更多信息在这里:https://developer.microsoft.com/en-us/graph/blogs/upcoming-changes-to-exchange-web-services-ews-api-for-office-365/

          【讨论】:

            猜你喜欢
            • 2011-12-03
            • 2017-07-28
            • 2019-06-05
            • 1970-01-01
            • 2011-06-24
            • 2011-03-30
            • 2011-04-18
            • 1970-01-01
            • 2015-04-10
            相关资源
            最近更新 更多