java - 电子邮件未在 @Async 注释方法中发送
问题描述
我正在尝试实现用户下载文件的功能。一般工作流程如下:
- 用户点击前端的下载按钮
- 后端会从request中接收下载信息,从数据库中获取数据,然后生成zip文件
- 该文件将上传到云存储(本例中为 Google)。
- 带有签名 URL 的电子邮件将发送给用户,以从云下载 zip 文件。
所有步骤 2、3 和 4 都将在使用 @Async 注释的方法中执行。问题是如果我重新启动后端服务器并只发送一个下载请求,一切都很好,这意味着可以接收电子邮件。 但是,在发送更多下载请求后它不起作用。不会再发送电子邮件。没有错误,没有警告,但是所有需要的数据都被正确接收,只是没有发送电子邮件。
任何人都知道它的问题是什么?
我的电子邮件发件人:
public class AbstractEmailSender {
public MimeMessage mimeMessage;
public MimeMessageHelper mimeMessageHelper;
public JavaMailSender javaMailSender;
private final String SENDER = MY_SEND_EMAIL_ADDRESS;
public final String USER_NAME_KEY = "username";
public AbstractEmailSender(JavaMailSender javaMailSender) throws MessagingException {
// this.javaMailSender = new JavaMailSenderImpl();
this.javaMailSender = javaMailSender;
this.doInitialization();
}
public void doInitialization() throws MessagingException {
this.mimeMessage = this.javaMailSender.createMimeMessage();
this.mimeMessageHelper = new MimeMessageHelper(mimeMessage, true);
}
public void setEmailContext(String receiver, String subject) throws MessagingException {
this.mimeMessageHelper.setSubject(subject);
this.mimeMessageHelper.setFrom(SENDER);
this.mimeMessageHelper.setTo(receiver);
}
}
@Component
public class DownloadDataSuccessEmailSender extends AbstractEmailSender implements MailService{
private final TemplateEngine templateEngine;
private final static String DOWNLOAD_DATA_SUCCESS_EMAIL_SUBJECT = XXXXXX;
private final static String SIGNED_URL_KEY = "signedUrl";
private final static String DOWNLOAD_EMAIL_TEMPLATE_NAME = "downloadDataSuccessEmail.html";
private static final Logger logger = LogManager.getLogger(DownloadDataSuccessEmailSender.class);
public DownloadDataSuccessEmailSender(JavaMailSender javaMailSender, TemplateEngine templateEngine) throws MessagingException {
super(javaMailSender);
this.templateEngine = templateEngine;
}
@Override
public void sendEmailWithSignedUrlToDownloadFile(URL signedUrl, String username, String receiver) {
// print the result to make sure all data are processed correctly, nothing wrong with
//this step
System.out.println(signedUrl);
System.out.println(username);
System.out.println(receiver);
try{
super.setEmailContext(receiver, DOWNLOAD_DATA_SUCCESS_EMAIL_SUBJECT);
Context context = new Context();
context.setVariable(this.USER_NAME_KEY, username);
context.setVariable(SIGNED_URL_KEY, signedUrl);
String email = this.templateEngine.process(DOWNLOAD_EMAIL_TEMPLATE_NAME, context);
this.mimeMessageHelper.setText(email, true);
this.javaMailSender.send(mimeMessage);
}catch (MailException | MessagingException e) {
logger.error("Email with download data error: ", e);
throw new EmailSendException(ErrorInfo.EMAIL_SEND_EXCEPTION.getCode(), ErrorInfo.EMAIL_SEND_EXCEPTION.getMessage());
}
}
}
电子邮件配置文件:
spring:
mail:
host: smtp.gmail.com
username: MY_EMAIL_ADDRESS
password: MY_PASSWORD
properties.mail.smtp:
auth: true
connectiontimeout: 60000
timeout: 60000
writetimeout: 50000
starttls.enable: true
port: 587
protocol: smtp
thymeleaf:
prefix: classpath:/templates/
处理所有逻辑的异步方法
@Override
@Async
@Transactional(timeout = DOWNLOAD_DATA_TRANSACTION_TIME_LIMIT)
public void downloadFile(SearchQuery query, DownloadRequestRecord downloadRecord){
String username = downloadRecord.getUsername();
String emailAddress = this.userService.getUserEmailAddressByUsername(username);
try{
// here ignore the parts to get data from database and generate zip file and check if the file is uploaded to cloud space successfully here
// ......
if (uploadFile == null) { // check if file exists
logger.error("File: {} does not exist in cloud!", zipFileName);
downloadRecord.setSuccess(0);
this.downloadDataFailMessageEmailSender.sendEmailWithDownloadDataFail(emailAddress, username, downloadRecord.getQuery(), downloadRecord.getDownloadTime()); // send email to inform user the download is fail
} else {
// file exists, generate signed URL and send email with download link
this.downloadDataSuccessEmailSender.sendEmailWithSignedUrlToDownloadFile(signedUrl, username, emailAddress);
downloadRecord.setSuccess(1);
}
} catch (IOException | EmailSendException ex) {
logger.error("Exception from downloading data: ", ex);
downloadRecord.setSuccess(0);
} finally {
this.userService.recordDownloadHistoryOfUser(downloadRecord);
}
}
我的线程池配置
@Configuration
public class AsyncConfig implements AsyncConfigurer {
private static final int CORE_POOL_SIZE = 6;
private static final int MAX_POOL_SIZE = 10;
private static final int QUEUE_CAPACITY = 100;
private static final String THREAD_NAME_PREFIX = "ThreadPoolTaskExecutor-";
private static final Logger logger = LogManager.getLogger(AsyncConfig.class);
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(CORE_POOL_SIZE);
executor.setMaxPoolSize(MAX_POOL_SIZE);
executor.setQueueCapacity(QUEUE_CAPACITY);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix(THREAD_NAME_PREFIX);
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
logger.error("ERROR: ", throwable);
}
};
}
}
解决方案
在 sendEmailWithSignedUrlToDownloadFile 创建 MimeMessage 使用
MimeMessage mimeMessage = mailSender.createMimeMessage();
而不是将 MimeMessage 的单个实例作为超类的成员
推荐阅读
- javascript - 在 JavaScript 中使用 PDF-lib 展平 PDF 时出现问题
- javascript - 遍历firebase数据库键中的所有子项
- java - java.lang.IllegalStateException:迁移在房间迁移中没有正确处理
- python - 如何通过抓取将新数据保存到现有的 csv 中
- python - wtforms CRUD - 在 SelectField 中设置默认值
- python - Why does my selection callback get called on my second Listbox?
- php - Yii2 SELECT * WHERE id = array()?
- java - 是否有带有非静态字段的 Java 接口替代方案?
- mysql - Sql Query 对按排名排序的数据进行排序,但乘以它发布的时间
- quill - 未捕获的类型错误:无法读取未定义的 Quill 羊皮纸的属性“Attributor”