我有一个 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);
即可。希望我能帮助别人。
编辑:我刚刚看到你发现了
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 属性配置它或设置一些有用的默认值。