mirror of https://github.com/halo-dev/halo
243 lines
7.8 KiB
Java
243 lines
7.8 KiB
Java
package run.halo.app.mail;
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.util.Arrays;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.function.Consumer;
|
|
import javax.mail.MessagingException;
|
|
import javax.mail.internet.InternetAddress;
|
|
import javax.mail.internet.MimeMessage;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.springframework.lang.NonNull;
|
|
import org.springframework.lang.Nullable;
|
|
import org.springframework.mail.javamail.JavaMailSender;
|
|
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
|
import org.springframework.mail.javamail.MimeMessageHelper;
|
|
import org.springframework.util.Assert;
|
|
import run.halo.app.exception.EmailException;
|
|
import run.halo.app.model.properties.EmailProperties;
|
|
import run.halo.app.service.OptionService;
|
|
|
|
/**
|
|
* Abstract mail service.
|
|
*
|
|
* @author johnniang
|
|
*/
|
|
@Slf4j
|
|
public abstract class AbstractMailService implements MailService {
|
|
|
|
private static final int DEFAULT_POOL_SIZE = 5;
|
|
|
|
protected final OptionService optionService;
|
|
|
|
private JavaMailSender cachedMailSender;
|
|
|
|
private MailProperties cachedMailProperties;
|
|
|
|
private String cachedFromName;
|
|
|
|
@Nullable
|
|
private ExecutorService executorService;
|
|
|
|
protected AbstractMailService(OptionService optionService) {
|
|
this.optionService = optionService;
|
|
}
|
|
|
|
@NonNull
|
|
public ExecutorService getExecutorService() {
|
|
if (this.executorService == null) {
|
|
this.executorService = Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);
|
|
}
|
|
return executorService;
|
|
}
|
|
|
|
public void setExecutorService(@Nullable ExecutorService executorService) {
|
|
this.executorService = executorService;
|
|
}
|
|
|
|
/**
|
|
* Test connection with email server.
|
|
*/
|
|
@Override
|
|
public void testConnection() {
|
|
JavaMailSender javaMailSender = getMailSender();
|
|
if (javaMailSender instanceof JavaMailSenderImpl) {
|
|
JavaMailSenderImpl mailSender = (JavaMailSenderImpl) javaMailSender;
|
|
try {
|
|
mailSender.testConnection();
|
|
} catch (Throwable e) {
|
|
throw new EmailException(e.getMessage(), e);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send mail template.
|
|
*
|
|
* @param callback mime message callback.
|
|
*/
|
|
protected void sendMailTemplate(@Nullable Consumer<MimeMessageHelper> callback) {
|
|
if (callback == null) {
|
|
log.info("Callback is null, skip to send email");
|
|
return;
|
|
}
|
|
|
|
// check if mail is enable
|
|
Boolean emailEnabled =
|
|
optionService.getByPropertyOrDefault(EmailProperties.ENABLED, Boolean.class);
|
|
|
|
if (!emailEnabled) {
|
|
// If disabled
|
|
log.info(
|
|
"Email has been disabled by yourself, you can re-enable it through email settings"
|
|
+ " on admin page.");
|
|
return;
|
|
}
|
|
|
|
// get mail sender
|
|
JavaMailSender mailSender = getMailSender();
|
|
printMailConfig();
|
|
|
|
// create mime message helper
|
|
MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage());
|
|
|
|
try {
|
|
// set from-name
|
|
messageHelper.setFrom(getFromAddress(mailSender));
|
|
// handle message set separately
|
|
callback.accept(messageHelper);
|
|
|
|
// get mime message
|
|
MimeMessage mimeMessage = messageHelper.getMimeMessage();
|
|
// send email
|
|
mailSender.send(mimeMessage);
|
|
|
|
log.info("Sent an email to [{}] successfully, subject: [{}], sent date: [{}]",
|
|
Arrays.toString(mimeMessage.getAllRecipients()),
|
|
mimeMessage.getSubject(),
|
|
mimeMessage.getSentDate());
|
|
} catch (Exception e) {
|
|
throw new EmailException("邮件发送失败,请检查 SMTP 服务配置是否正确", e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send mail template if executor service is enable.
|
|
*
|
|
* @param callback callback message handler
|
|
* @param tryToAsync if the send procedure should try to asynchronous
|
|
*/
|
|
protected void sendMailTemplate(boolean tryToAsync,
|
|
@Nullable Consumer<MimeMessageHelper> callback) {
|
|
ExecutorService executorService = getExecutorService();
|
|
if (tryToAsync) {
|
|
// send mail asynchronously
|
|
executorService.execute(() -> sendMailTemplate(callback));
|
|
} else {
|
|
// send mail synchronously
|
|
sendMailTemplate(callback);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get java mail sender.
|
|
*
|
|
* @return java mail sender
|
|
*/
|
|
@NonNull
|
|
private synchronized JavaMailSender getMailSender() {
|
|
if (this.cachedMailSender == null) {
|
|
// create mail sender factory
|
|
MailSenderFactory mailSenderFactory = new MailSenderFactory();
|
|
// get mail sender
|
|
this.cachedMailSender = mailSenderFactory.getMailSender(getMailProperties());
|
|
}
|
|
|
|
return this.cachedMailSender;
|
|
}
|
|
|
|
/**
|
|
* Get from-address.
|
|
*
|
|
* @param javaMailSender java mail sender.
|
|
* @return from-name internet address
|
|
* @throws UnsupportedEncodingException throws when you give a wrong character encoding
|
|
*/
|
|
private synchronized InternetAddress getFromAddress(@NonNull JavaMailSender javaMailSender)
|
|
throws UnsupportedEncodingException {
|
|
Assert.notNull(javaMailSender, "Java mail sender must not be null");
|
|
|
|
if (StringUtils.isBlank(this.cachedFromName)) {
|
|
// set personal name
|
|
this.cachedFromName =
|
|
optionService.getByPropertyOfNonNull(EmailProperties.FROM_NAME).toString();
|
|
}
|
|
|
|
if (javaMailSender instanceof JavaMailSenderImpl) {
|
|
// get user name(email)
|
|
JavaMailSenderImpl mailSender = (JavaMailSenderImpl) javaMailSender;
|
|
String username = mailSender.getUsername();
|
|
|
|
// build internet address
|
|
return new InternetAddress(username, this.cachedFromName,
|
|
mailSender.getDefaultEncoding());
|
|
}
|
|
|
|
throw new UnsupportedOperationException(
|
|
"Unsupported java mail sender: " + javaMailSender.getClass().getName());
|
|
}
|
|
|
|
/**
|
|
* Get mail properties.
|
|
*
|
|
* @return mail properties
|
|
*/
|
|
@NonNull
|
|
private synchronized MailProperties getMailProperties() {
|
|
if (cachedMailProperties == null) {
|
|
// create mail properties
|
|
MailProperties mailProperties = new MailProperties(log.isDebugEnabled());
|
|
|
|
// set properties
|
|
mailProperties
|
|
.setHost(optionService.getByPropertyOrDefault(EmailProperties.HOST, String.class));
|
|
mailProperties.setPort(
|
|
optionService.getByPropertyOrDefault(EmailProperties.SSL_PORT, Integer.class));
|
|
mailProperties.setUsername(
|
|
optionService.getByPropertyOrDefault(EmailProperties.USERNAME, String.class));
|
|
mailProperties.setPassword(
|
|
optionService.getByPropertyOrDefault(EmailProperties.PASSWORD, String.class));
|
|
mailProperties.setProtocol(
|
|
optionService.getByPropertyOrDefault(EmailProperties.PROTOCOL, String.class));
|
|
this.cachedMailProperties = mailProperties;
|
|
}
|
|
|
|
return this.cachedMailProperties;
|
|
}
|
|
|
|
/**
|
|
* Print mail configuration.
|
|
*/
|
|
private void printMailConfig() {
|
|
if (!log.isDebugEnabled()) {
|
|
return;
|
|
}
|
|
|
|
// get mail properties
|
|
MailProperties mailProperties = getMailProperties();
|
|
log.debug(mailProperties.toString());
|
|
}
|
|
|
|
/**
|
|
* Clear cached instance.
|
|
*/
|
|
protected void clearCache() {
|
|
this.cachedMailSender = null;
|
|
this.cachedFromName = null;
|
|
this.cachedMailProperties = null;
|
|
log.debug("Cleared all mail caches");
|
|
}
|
|
}
|