All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xlrit.gears.plugin.mail.MailBatchSender Maven / Gradle / Ivy

The newest version!
package com.xlrit.gears.plugin.mail;

import java.time.OffsetDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.xlrit.gears.base.execution.Execution;
import com.xlrit.gears.base.schedule.ScheduledRunnable;
import com.xlrit.gears.base.model.Mail;
import com.xlrit.gears.base.repository.MailRepository;

import jakarta.mail.MessagingException;
import jakarta.mail.internet.MimeMessage;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.mail.MailAuthenticationException;
import org.springframework.mail.MailSendException;
import org.springframework.stereotype.Component;

import static com.xlrit.gears.plugin.mail.MailHelper.HEADER_MAIL_ID;

@Component
@RequiredArgsConstructor
public class MailBatchSender extends ScheduledRunnable {
	private static final Logger LOG = LoggerFactory.getLogger(MailBatchSender.class);

	private final MailProperties mailProperties;
	private final MailRepository mailRepository;
	private final MailHelper mailHelper;

	@Override
	protected boolean isEnabled() {
		return mailProperties.isEnabled(MailProperties.Mode.BATCH);
	}

	@Override
	protected String getCronExpression() {
		return mailProperties.getCron();
	}

	@Override
	protected void runScheduled() {
		LOG.debug("Running now...");

		try {
			while (true) {
				List mails = mailRepository.getMailsToSend(mailProperties.getBatchSize());
				LOG.debug("Mails to send: {}", mails.size());
				if (mails.isEmpty()) break;
				sendMails(mails);
			}
		}
		catch (MailAuthenticationException e) {
			LOG.error("Unable to send mails due to authentication failure: " + e.getMessage(), e);
		}
	}

	private void sendMails(List mails) {
		MimeMessage[] messages = mails.stream()
			.map(mailHelper::createMessage)
			.filter(Objects::nonNull)
			.toArray(MimeMessage[]::new);

		OffsetDateTime now = OffsetDateTime.now();
		SendResult result = doSendMails(messages);
		LOG.info("{} mails sent; {} failures", result.getSuccesfull().size(), result.getFailed().size());
		Set failedIds = result.getFailedIds();

		for (Mail mail : mails) {
			if (failedIds.contains(mail.getId())) {
				mail.setAttempts(mail.getAttempts() + 1);
				mail.setLastAttempt(now);
			}
			else {
				mailRepository.remove(mail, Execution.NONE);
			}
		}
	}

	private SendResult doSendMails(MimeMessage[] messages) {
		try {
			mailHelper.send(messages);
			return new SendResult(List.of(messages), List.of());
		}
		catch (MailSendException e) {
			Map failedMessages = e.getFailedMessages();
			List successful = new ArrayList<>();
			List failed = new ArrayList<>();
			for (MimeMessage message : messages) {
				List target = failedMessages.containsKey(message) ? failed : successful;
				target.add(message);
			}
			return new SendResult(successful, failed);
		}
	}

	@Data
	@RequiredArgsConstructor
	private static class SendResult {
		private final List succesfull;
		private final List failed;

		public Set getFailedIds() {
			return failed.stream().map(this::extractMailId).collect(Collectors.toSet());
		}

		@SneakyThrows(MessagingException.class)
		private String extractMailId(MimeMessage message) {
			return message.getHeader(HEADER_MAIL_ID, null);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy