已解决:如何从多个 SMTP 服务器动态发送电子邮件(Java SpringBoot)

问题描述 投票:0回答:1

现状

我有一个 Java SpringBoot api,目前它能够使用 javax.mail.MimeMessage 动态发送电子邮件。凭据作为参数(电子邮件地址、密码、SMTP 服务器、SMTP 端口)传递。当我启动应用程序并发送第一封电子邮件时,一切正常。

问题

但是,当我尝试从不同的 SMTP 服务器发送另一封电子邮件时,该电子邮件似乎是从第一个 SMTP 服务器和凭据发送的。例如,在 Googlemail 中,每封电子邮件都会显示发件人以及发送邮件的 (SMTP-) 服务器。虽然发送的电子邮件地址显示新的电子邮件地址,但“发送自”(SMTP 服务器)仍显示旧的 SMTP 服务器。

目标

所以我想要的是能够从单独的 SMTP 服务器和电子邮件地址发送多封电子邮件,并通过参数传递。

控制器

@RequestMapping("/send-email")
public class EmailController {

    public EmailController(){}

    @PostMapping
    public SentEmail sendEmail(@RequestBody SendEmailInformation sendEmailInformation) {
        EmailService emailService = new EmailService();
        return emailService.sendEmail(sendEmailInformation);
    }

}

电子邮件服务

{
    private Transport transport;

    public EmailService() {}

    public void sendEmail(SendEmailInformation sendEmailInformation) {
        try{
            String fromEmail = sendEmailInformation.getEmailAddress();
            String password = sendEmailInformation.getPassword();
            String toEmail = sendEmailInformation.getEmail();

            Properties props = new Properties();
            props.put("mail.smtp.host", sendEmailInformation.getSmtpServer());
            props.put("mail.smtp.port", sendEmailInformation.getSmtpPort());
            props.put("mail.smtp.starttls.enable", "true");
            props.put("mail.smtp.auth", "true");

            Authenticator auth = new Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(fromEmail, password);
                }
            };

            Session session = Session.getDefaultInstance(props, auth);

            MimeMessage msg = new MimeMessage(session);
            msg.addHeader("Content-type", "text/HTML; charset=UTF-8");
            msg.addHeader("format", "flowed");
            msg.addHeader("Content-Transfer-Encoding", "8bit");

            msg.setFrom(new InternetAddress(fromEmail));
            msg.setReplyTo(InternetAddress.parse(sendEmailInformation.getEmail(), false));
            msg.setSubject(sendEmailInformation.getSubject(), "UTF-8");
            msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail, false));
            BodyPart messageBodyPart = new MimeBodyPart();

            messageBodyPart.setText(sendEmailInformation.getMessage());

            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(messageBodyPart);

            msg.setContent(multipart);

            transport = session.getTransport("smtp");
            transport.connect();
            transport.sendMessage(msg,msg.getRecipients(Message.RecipientType.TO));
            transport.close();
        }catch (Exception e) {
            try {
                transport.close();
            }catch (Exception ignored) {

            }
            e.printStackTrace();
            throw new CouldNotSendEmailException();
        }
    }
}

我已经尝试过了

起初,我将电子邮件服务作为@Bean,并认为我应该像现在一样尝试为每个调用创建一个新对象。所以使用@Bean是行不通的。另外,根据我的理解,用 Transport.close() 关闭 Transport 对象;最后应该可以解决我的问题,但没有。

问题

有人有想法,什么可以解决我的问题吗?

提前致谢。

编辑

解决方案

连续多天寻找我的代码,从未看到错误,然后发布这个问题,几分钟后就想到

Session session = Session.getDefaultInstance(props, auth);
可能是问题所在......是的!这始终使用相同的 Session 对象,而不是创建一个新的。

对于那些面临同样问题的人: 只需使用

Session session = Session.getInstance(props, auth);
即可。希望我能帮助别人。

java spring-boot email smtp mime-message
1个回答
0
投票

编辑:我刚刚看到你发现了

Session.defaultInstance
的问题,但下面的解决方案仍然值得考虑。


我可以建议一个不同的库来解决这个问题吗?使用开源Simple Java Mail可以解决您的问题,如下所示:

public class EmailService {

    public EmailService() {}

    public void sendEmail(SendEmailInformation sendEmailInformation) {
        try {
            String fromEmail = sendEmailInformation.getEmailAddress();

            Mailer mailer = MailerBuilder
                    .withSMTPServer(sendEmailInformation.getSmtpServer(), sendEmailInformation.getSmtpPort(), fromEmail)
                    .withSMTPServerPassword(sendEmailInformation.getPassword())
                    .withTransportStrategy(TransportStrategy.SMTP_TLS)
                    .buildMailer();

            Email email = EmailBuilder.startingBlank()
                    .from(fromEmail)
                    .to(sendEmailInformation.getEmail())
                    .withHeader("format", "flowed")
                    .withSubject(sendEmailInformation.getSubject())
                    .withPlainText(sendEmailInformation.getMessage())
                    //.withHTMLText() for HTML messages
                    .withContentTransferEncoding(ContentTransferEncoding.BIT8)
                    .buildEmail();

            mailer.sendMail(email);
        } catch (MailException e) {
            e.printStackTrace();
            throw new CouldNotSendEmailException();
        }
    }
}

这不仅更干净,而且在许多情况下对于电子邮件客户端来说也更好(请参阅为什么 RFC 合规性很重要)。

另一件事是你可以注入一个 EmailBuilder,这样你就可以(部分)从 Spring 属性配置它或设置一些有用的默认值。

© www.soinside.com 2019 - 2024. All rights reserved.