Jar:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
MailSenderDelegateNN
import com.aerohive.core.service.BaseMailSettingsVo;
import com.aerohive.core.service.BaseMailSettingsVo.BaseMailServiceEncrytption;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.mail.internet.MimeMessage;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Properties;
/*
* MailSenderDelegateNN is a singleton bean.
*/
@Slf4j
@Service
public class MailSenderDelegateNN implements JavaMailSender {
public static final String MAIL_SETTING_REDIS_KEY = "mail.sender.delegate.settings.key";
@Autowired
private JavaMailSenderImpl defaultMailSender;
private JavaMailSenderImpl customMailSender;
private SimpleMailMessage customMailInfo;
@Getter
@Autowired
@Qualifier("coreStringRedisTemplate")
private StringRedisTemplate stringRedisTemplate;
@Getter
private String mailSettingsJsonStrLocal;
@Value("${mailserver.host}") private String defaultMailServerHost;
@Value("${mailserver.port}") private int defaultMailServerPort;
@Value("${mailserver.username}") private String defaultMailServerUsername;
@Value("${mailserver.password}") private String defaultMailServerPassword;
@Value("${mail.smtp.timeout}") private int smtpTimeout;
@Value("${mail.acct.sender}") private String sendFrom;
@Value("${mail.sender.is.default}") private boolean isDefaultMailSender;
public MailSenderDelegateNN() {
customMailSender = new JavaMailSenderImpl();
customMailInfo = new SimpleMailMessage();
}
@PostConstruct
void initBean() {
customMailSender.setHost(defaultMailServerHost);
customMailSender.setPort(defaultMailServerPort);
customMailSender.setUsername(defaultMailServerUsername);
customMailSender.setPassword(defaultMailServerPassword);
customMailInfo.setFrom(sendFrom);
}
public void setupCustomMailSenderDelegate(BaseMailSettingsVo mailSettings) {
if (isDefaultMailSender) {
return;
}
setupMailSenderInfo(customMailSender, customMailInfo, mailSettings);
//update local copy
mailSettingsJsonStrLocal = JsonUtil.toJsonString(mailSettings);
//update cache
stringRedisTemplate.opsForValue().set(MAIL_SETTING_REDIS_KEY, mailSettingsJsonStrLocal);
}
public void setupMailSenderInfo(JavaMailSenderImpl mailSender, SimpleMailMessage mailInfo,
BaseMailSettingsVo mailSettings) {
log.info("Setup mail settings {}", mailSettings);
mailSender.setHost(mailSettings.getSmtpServer());
mailSender.setPort(mailSettings.getSmtpPort());
Properties props = mailSender.getJavaMailProperties();
props.setProperty("mail.smtp.host", mailSettings.getSmtpServer());
props.setProperty("mail.smtp.port", String.valueOf(mailSettings.getSmtpPort()));
props.setProperty("mail.smtp.protocol", "smtp");
props.setProperty("mail.smtp.timeout", String.valueOf(smtpTimeout));
props.setProperty("mail.smtp.socketFactory.port ", String.valueOf(mailSettings.getSmtpPort()));
props.remove("mail.smtp.socketFactory.class");
props.remove("mail.smtp.socketFactory.fallback");
props.setProperty("mail.smtp.ssl", "false");
props.setProperty("mail.smtp.starttls.enable", "false");
props.setProperty("mail.smtp.ssl.trust", "*");
props.setProperty("mail.debug", "true");
if (mailSettings.getEncryptType() == BaseMailServiceEncrytption.BASE_MAIL_SERVICE_ENCRYPT_SSL) {
props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.ssl", "true");
props.setProperty("mail.smtp.ssl.enable", "true");
props.setProperty("mail.smtp.protocol", "smtps");
mailSender.setProtocol("smtps");
}
else if (mailSettings.getEncryptType() == BaseMailServiceEncrytption.BASE_MAIL_SERVICE_ENCRYPT_TLS) {
props.setProperty("mail.smtp.starttls.enable", "true");
}
if (mailSettings.getSupportPwdAuth()) {
final String usr = mailSettings.getUsername();
final String pwd = mailSettings.getPassword();
mailSender.setUsername(usr);
mailSender.setPassword(pwd);
props.setProperty("mail.smtp.auth", "true");
props.setProperty("mail.smtp.username", usr);
props.setProperty("mail.smtp.password", pwd);
}
else {
props.setProperty("mail.smtp.auth", "false");
}
mailSender.setJavaMailProperties(props);
if (mailInfo != null) {
mailInfo.setFrom(mailSettings.getSendFrom());
if (mailSettings.getCcEmailList() != null) {
String[] ccList = Arrays.copyOf(mailSettings.getCcEmailList().toArray(),
mailSettings.getCcEmailList().size(), String[].class);
mailInfo.setCc(ccList);
}
if (mailSettings.getBccEmailList() != null) {
String[] bccList = Arrays.copyOf(mailSettings.getBccEmailList().toArray(),
mailSettings.getBccEmailList().size(), String[].class);
mailInfo.setBcc(bccList);
}
}
}
private void updateMailSendInfoFromCache() {
if (isDefaultMailSender) {
return;
}
String mailSettingsJsonStrCache = stringRedisTemplate.opsForValue().get(MAIL_SETTING_REDIS_KEY);
if ((mailSettingsJsonStrCache == null) || mailSettingsJsonStrCache.equals(mailSettingsJsonStrLocal)) {
return;
} else {
log.info("cached mail settings {} vs local mail settings {}",
mailSettingsJsonStrCache, mailSettingsJsonStrLocal);
BaseMailSettingsVo mailSettingsCache = JsonUtil.toObject(mailSettingsJsonStrCache, BaseMailSettingsVo.class);
try {
setupCustomMailSenderDelegate(mailSettingsCache);
} catch (Exception e) {
log.error("setupCustomMailSenderDelegate failed {}", mailSettingsCache, e);
}
}
}
public JavaMailSenderImpl getCustomMailSender() {
updateMailSendInfoFromCache();
return customMailSender;
}
public SimpleMailMessage getCustomMailInfo() {
updateMailSendInfoFromCache();
return customMailInfo;
}
@Override
public MimeMessage createMimeMessage() {
if (isDefaultMailSender) {
return defaultMailSender.createMimeMessage();
} else {
return customMailSender.createMimeMessage();
}
}
@Override
public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {
if (isDefaultMailSender) {
return defaultMailSender.createMimeMessage(contentStream);
} else {
return customMailSender.createMimeMessage(contentStream);
}
}
// example
@Override
public void send(MimeMessage mimeMessage) throws MailException {
if (isDefaultMailSender) {
defaultMailSender.send(mimeMessage);
} else {
updateMailSendInfoFromCache();
customMailSender.send(mimeMessage);
}
}
@Override
public void send(MimeMessage[] mimeMessages) throws MailException {
if (isDefaultMailSender) {
defaultMailSender.send(mimeMessages);
} else {
updateMailSendInfoFromCache();
customMailSender.send(mimeMessages);
}
}
// example
@Override
public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {
if (isDefaultMailSender) {
defaultMailSender.send(mimeMessagePreparator);
} else {
updateMailSendInfoFromCache();
customMailSender.send(mimeMessagePreparator);
}
}
@Override
public void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException {
if (isDefaultMailSender) {
defaultMailSender.send(mimeMessagePreparators);
} else {
updateMailSendInfoFromCache();
customMailSender.send(mimeMessagePreparators);
}
}
@Override
public void send(SimpleMailMessage simpleMessage) throws MailException {
if (isDefaultMailSender) {
defaultMailSender.send(simpleMessage);
} else {
updateMailSendInfoFromCache();
customMailSender.send(simpleMessage);
}
}
@Override
public void send(SimpleMailMessage[] simpleMessages) throws MailException {
if (isDefaultMailSender) {
defaultMailSender.send(simpleMessages);
} else {
updateMailSendInfoFromCache();
customMailSender.send(simpleMessages);
}
}
}
EmailSender
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.velocity.app.VelocityEngine;
import org.hibernate.annotations.common.util.StringHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.mail.javamail.MimeMessagePreparator;
import org.springframework.stereotype.Component;
import org.springframework.ui.velocity.VelocityEngineUtils;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Slf4j
@Component
public class EmailSender {
@Autowired private MailSenderDelegateNN mailSenderDelegate;
@Value("${mail.sender}") private String sendFrom;
@Value("${mail.is.custom}") private boolean isCustom;
String DEFAULT_STRING_ENCODING = "UTF-8";
// one type
private MimeMessage initEmail(EmailMessage message, String content) throws Exception {
MimeMessage mimeMessage = mailSenderDelegate.createMimeMessage();
MimeMessageHelper messageHelper = null;
if (CollectionUtils.isEmpty(message.getAttachUrls())) {
messageHelper = new MimeMessageHelper(mimeMessage, DEFAULT_STRING_ENCODING);
} else {
messageHelper = new MimeMessageHelper(mimeMessage, true, DEFAULT_STRING_ENCODING);
}
try {
messageHelper.setTo(message.getToEmailList());
messageHelper.setSubject(message.getSubject());
messageHelper.setText(content, true);
if (CollectionUtils.isNotEmpty(message.getAttachUrls())) {
for (String url : message.getAttachUrls()) {
if (StringHelper.isNotEmpty(url)) {
InputStream is = getAttachFile(url);
messageHelper.addAttachment(url, new ByteArrayResource(IOUtils.toByteArray(is)));
}
}
}
customMailInfo(messageHelper);
//over write by EmailMessage
String[] ccEmailList = EmailUtil.parseEmailAddress(message.getCc());
if (ArrayUtils.isNotEmpty(ccEmailList)) {
messageHelper.setCc(ccEmailList);
log.info("overwrite cclist:{}", Arrays.toString(ccEmailList));
}
if (StringHelper.isNotEmpty(message.getSender()) && EmailUtil.isValidEmailAddress(message.getSender())) {
messageHelper.setFrom(message.getSender());
log.info("overwrite sendFrom:{}", message.getSender());
}
}
catch (MessagingException e) {
log.error("initEmail error.Message:{}", message.toString(), e);
}
return mimeMessage;
}
private void customMailInfo(MimeMessageHelper messageHelper) throws MessagingException {
messageHelper.setFrom(sendFrom);
if (isCustom) {
SimpleMailMessage customMailInfo = mailSenderDelegate.getCustomMailInfo();
String from = customMailInfo.getFrom();
String[] ccs = customMailInfo.getCc();
String[] bccs = customMailInfo.getBcc();
setUpMailInfo(messageHelper, from, ccs, bccs);
log.info("Sending email use HMVA setting: from;{}, CC email:{}, BCC email:{}.", from, Arrays.toString(ccs),
Arrays.toString(bccs));
}
}
private void setUpMailInfo(MimeMessageHelper messageHelper, String from, String[] cc, String[] bcc)
throws MessagingException {
if (StringHelper.isNotEmpty(from)) {
messageHelper.setFrom(from);
}
if (ArrayUtils.isNotEmpty(cc)) {
messageHelper.setCc(cc);
}
if (ArrayUtils.isNotEmpty(bcc)) {
messageHelper.setBcc(bcc);
}
}
@Autowired
private VelocityEngine velocityEngine;
@Value("${aerohive.email.resource.server:http://127.0.0.1:8080/hm-webapp}")
private String emailResourceServer;
public void sendAlertEmail(NotifyContext context) {
final Map<String, Object> params = buildParams(context);
sendEmail(buildMimeMessagePreparator(params, context));
}
private Map<String, Object> buildParams(NotifyContext context) {
Map<String, Object> params = context.buildParams();
params.put("server", emailResourceServer);
return params;
}
private MimeMessagePreparator buildMimeMessagePreparator(final Map<String, Object> params,
final NotifyContext context) {
log.debug("Preparing to send email to " + context.getToEmailList());
return new MimeMessagePreparator() {
@Override
public void prepare(MimeMessage mimeMessage) throws Exception {
MimeMessageHelper message = new MimeMessageHelper(mimeMessage, true, "UTF-8");
message.setTo(context.getToEmailList());
message.setFrom(sendFrom);
message.setSubject(context.getSubject());
String text = VelocityEngineUtils
.mergeTemplateIntoString(velocityEngine, "mail/view/issue-email.vm", "UTF-8", params);
message.setText(text, true);
}
};
}
private void sendEmail(final MimeMessagePreparator preparator) {
try {
mailSenderDelegate.send(preparator);
}
catch (Exception e) {
log.error("Error occurred when sending email", e);
}
finally {
log.debug("End of sending email");
}
}
@Data
class EmailMessage {
private String subject;
private String cc; // copy to
private List<String> attachUrls; // attach
private String message;
private String sender;
private String toEmailList;
private Long postTime;
private Long sendTime;
private String customerId;
private long ownerId;
private long userId;
}
@Data
class NotifyContext extends EmailMessage {
}
}
final class EmailUtil {
private static final String SEPARATOR = ";";
private static final Pattern p = Pattern.compile("\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*");
private EmailUtil() {
}
public static String[] parseEmailAddress(String address) {
List<String> list = new ArrayList<>();
if (null != address) {
String[] addressArray = address.trim().split(SEPARATOR);
for (String mailTo : addressArray) {
if (mailTo != null && isValidEmailAddress(mailTo)) {
list.add(mailTo.trim());
}
}
}
return Arrays.copyOf(list.toArray(), list.size(), String[].class);
}
public static boolean isValidEmailAddress(String emailAddress) {
Matcher m = p.matcher(emailAddress);
return m.matches();
}
}