使用 Office 365 时,设置 mail.smtp.connectiontimeout 会延长请求

问题描述

我们正在使用 org.springframework.mail.javamail.JavaMailSender 通过 Office 365 帐户和 SMTP 在电子邮件服务中发送邮件,并在 application.yml 中设置以下参数:

spring:
  mail:
    host: ${EMAIL_HOST:smtp.office365.com}
    port: ${EMAIL_PORT:587}
    username: ${EMAIL_USERNAME}
    password: ${EMAIL_PASSWORD}
    properties:
        mail:
          smtp:
            auth: true
            connectiontimeout: 5000
            timeout: 5000
            writetimeout: 5000
            starttls:
              enable: true
            socketFactory:
              port: 465
              class: javax.net.ssl.SSLSocketFactory

奇怪的是:如果我们将connectiontimeout设置为5s,服务会在5s后得到响应。如果我们将其设置为 20 秒,则 o365 会在 20 秒后响应。 我的期望是 是发送可能需要的最长时间,而不是实际时间。 有趣的是,当设置除 office365 之外的其他提供商时,connectiontimeout 会按预期工作。

有没有人也有这个问题,也许知道如何解决

我们的发件人服务:

@PostMapping
@ResponseStatus(HttpStatus.ACCEPTED)
public void sendMail(@RequestHeader(name = "X-API-KEY",required = true) String requestApiKey,@Valid @RequestBody EmailSendRequest email,HttpServletResponse response) {
        if(!apiKey.equals(requestApiKey)){
            LOGGER.error("Unauthorized api key" + requestApiKey);
            throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
        }
        try {
            LOGGER.info("Received request to send mail Subject=[{}] To=[{}] From=[{}]",email.getSubject(),email.getTo(),email.getFrom());

            MimeMessage message = mailSender.createMimeMessage();
            message.setFrom(new InternetAddress(email.getFrom().getEmail()));

            message.addRecipients(Message.RecipientType.TO,toAddressArray(email.getTo()));
            message.addRecipients(Message.RecipientType.CC,toAddressArray(email.getCc()));
            message.addRecipients(Message.RecipientType.BCC,toAddressArray(email.getBcc()));

            message.setSubject(email.getSubject());
            message.setSentDate(new Date());

            Multipart multipart = new MimeMultipart();

            MimeBodyPart messageText = new MimeBodyPart();
            messageText.setContent(email.getContent().getValue(),email.getContent().getType() == null ? DEFAULT_CONTENT_MIMETYPE : email.getContent().getType());
            multipart.addBodyPart(messageText);

            addAttachments(multipart,email.getAttachments());
            message.setContent(multipart);

            if(message.getRecipients(Message.RecipientType.TO) != null ||
                    message.getRecipients(Message.RecipientType.CC) != null ||
                    message.getRecipients(Message.RecipientType.BCC) != null)
            {
                mailSender.send(message);
            }
            else {
                LOGGER.warn("Email not send! No recipients or all ignored.");
                response.setHeader("X-Ignored","true");
            }

            LOGGER.info("Mail Subject=[{}] To=[{}}] From=[{}] successfully sent.",email.getFrom());
        } catch (MessagingException e) {
            LOGGER.error("Error sending mail Subject=[{}] To=[{}] From=[{}]:",email.getFrom(),e);
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
        } catch (MailSendException mailSendException) {
            Exception[] exceptions = mailSendException.getMessageExceptions();
            for (Exception e : exceptions){
                if (e instanceof SMTPSendFailedException && (((SMTPSendFailedException)e).getReturnCode() == 554)){
                    LOGGER.error("Error sending mail Subject=[{}] To=[{}] From=[{}]: This sender mail address is not allowed.",email.getFrom());
                    throw new ResponseStatusException(HttpStatus.FORBIDDEN);
                }
            }
            LOGGER.error("Error sending mail Subject=[{}] To=[{}] From=[{}]:",mailSendException);
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
        } catch (MailAuthenticationException e) {
            LOGGER.error("Error sending mail Subject=[{}] To=[{}] From=[{}]: Wrong SMTP login credentials provided. \nMSG:{}",e.getMessage());

            throw new ResponseStatusException(HttpStatus.NETWORK_AUTHENTICATION_required);
        }
    }

解决方法

看来,SocketFactory 是造成这种行为的原因。从 application.yml 中删除以下几行会使应用程序按预期工作:

 socketFactory:
              port: 465
              class: javax.net.ssl.SSLSocketFactory

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...