/*
* Symphony - A modern community (forum/SNS/blog) platform written in Java.
* Copyright (C) 2012-2017, b3log.org & hacpai.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.b3log.symphony.util;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import org.apache.commons.lang.StringUtils;
import org.b3log.latke.Keys;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.json.JSONObject;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileTypeMap;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Mail utilities.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @author <a href="http://blog.thinkjava.top">VirutalPier</a>
* @author <a href="https://github.com/snowflake3721">snowflake</a>
* @version 1.2.6.6, Mar 10, 2017
* @since 1.3.0
*/
public final class Mails {
/**
* Template name - verifycode.
*/
public static final String TEMPLATE_NAME_VERIFYCODE = "sym_verifycode";
/**
* Template name - weekly.
*/
public static final String TEMPLATE_NAME_WEEKLY = "sym_weekly";
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(Mails.class);
/**
* Mail channel.
*/
private static final String MAIL_CHANNEL = Symphonys.get("mail.channel");
/**
* SendCloud API user.
*/
private static final String SENDCLOUD_API_USER = Symphonys.get("mail.sendcloud.apiUser");
/**
* SendCloud API key.
*/
private static final String SENDCLOUD_API_KEY = Symphonys.get("mail.sendcloud.apiKey");
/**
* SendCloud from.
*/
private static final String SENDCLOUD_FROM = Symphonys.get("mail.sendcloud.from");
/**
* SendCloud batch API User.
*/
private static final String SENDCLOUD_BATCH_API_USER = Symphonys.get("mail.sendcloud.batch.apiUser");
/**
* SendCloud batch API key.
*/
private static final String SENDCLOUD_BATCH_API_KEY = Symphonys.get("mail.sendcloud.batch.apiKey");
/**
* SendCloud batch sender email.
*/
private static final String SENDCLOUD_BATCH_FROM = Symphonys.get("mail.sendcloud.batch.from");
/**
* Aliyun accesskey.
*/
private static final String ALIYUN_ACCESSKEY = Symphonys.get("mail.aliyun.accessKey");
/**
* Aliyun access secret.
*/
private static final String ALIYUN_ACCESSSECRET = Symphonys.get("mail.aliyun.accessSecret");
/**
* Aliyun from.
*/
private static final String ALIYUN_FROM = Symphonys.get("mail.aliyun.from");
/**
* Aliyun batch from.
*/
private static final String ALIYUN_BATCH_FROM = Symphonys.get("mail.aliyun.batch.from");
/**
* Template configuration.
*/
private static final Configuration TEMPLATE_CFG = new Configuration(Configuration.VERSION_2_3_23);
static {
try {
TEMPLATE_CFG.setDirectoryForTemplateLoading(new File(Mails.class.getResource("/mail_tpl").toURI()));
TEMPLATE_CFG.setDefaultEncoding("UTF-8");
TEMPLATE_CFG.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
TEMPLATE_CFG.setLogTemplateExceptions(false);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Loads mail templates failed", e);
}
}
/**
* Private constructor.
*/
private Mails() {
}
/**
* Sends a HTML mail.
*
* @param fromName the specified from name
* @param subject the specified subject
* @param toMail the specified receiver mail
* @param templateName the specified template name
* @param dataModel the specified data model
*/
public static void sendHTML(final String fromName, final String subject, final String toMail,
final String templateName, final Map<String, Object> dataModel) {
if ("sendcloud".equals(MAIL_CHANNEL)) {
if (StringUtils.isBlank(SENDCLOUD_API_USER) || StringUtils.isBlank(SENDCLOUD_API_KEY)) {
LOGGER.warn("Please configure [#### SendCloud Mail channel ####] section in symphony.properties for sending mail");
return;
}
} else if ("aliyun".equals(MAIL_CHANNEL)) {
if (StringUtils.isBlank(ALIYUN_ACCESSKEY) || StringUtils.isBlank(ALIYUN_ACCESSSECRET)) {
LOGGER.warn("Please configure [#### Aliyun Mail channel ####] section in symphony.properties for sending mail");
return;
}
} else {
if (StringUtils.isBlank(MailSender.username) || StringUtils.isBlank(MailSender.password)) {
LOGGER.warn("Please configure [#### Local Mail channel ####] section in symphony.properties for sending mail");
return;
}
}
Keys.fillServer(dataModel);
Keys.fillRuntime(dataModel);
try {
final Map<String, Object> formData = new HashMap<>();
final Template template = TEMPLATE_CFG.getTemplate(templateName + ".ftl");
final StringWriter stringWriter = new StringWriter();
template.process(dataModel, stringWriter);
stringWriter.close();
final String html = stringWriter.toString();
if ("aliyun".equals(MAIL_CHANNEL)) {
aliSendHtml(ALIYUN_FROM, fromName, subject, toMail, html, ALIYUN_ACCESSKEY, ALIYUN_ACCESSSECRET);
return;
} else if ("local".equals(MAIL_CHANNEL.toLowerCase())) {
MailSender.getInstance().sendHTML(fromName, subject, toMail, html);
return;
}
// SendCloud
formData.put("apiUser", SENDCLOUD_API_USER);
formData.put("apiKey", SENDCLOUD_API_KEY);
formData.put("from", SENDCLOUD_FROM);
formData.put("fromName", fromName);
formData.put("subject", subject);
formData.put("to", toMail);
formData.put("html", html);
final HttpResponse response = HttpRequest.post("http://api.sendcloud.net/apiv2/mail/send").form(formData).send();
LOGGER.debug(response.bodyText());
response.close();
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Send mail error", e);
}
}
/**
* Batch send HTML mails.
*
* @param fromName the specified from name
* @param subject the specified subject
* @param toMails the specified receiver mails
* @param templateName the specified template name
* @param dataModel the specified data model
*/
public static void batchSendHTML(final String fromName, final String subject, final List<String> toMails,
final String templateName, final Map<String, Object> dataModel) {
if ("sendcloud".equals(MAIL_CHANNEL)) {
if (StringUtils.isBlank(SENDCLOUD_BATCH_API_USER) || StringUtils.isBlank(SENDCLOUD_BATCH_API_KEY)) {
LOGGER.warn("Please configure [#### SendCloud Mail channel ####] section in symphony.properties for sending mail");
return;
}
} else if ("aliyun".equals(MAIL_CHANNEL)) {
if (StringUtils.isBlank(ALIYUN_ACCESSKEY) || StringUtils.isBlank(ALIYUN_ACCESSSECRET)) {
LOGGER.warn("Please configure [#### Aliyun Mail channel ####] section in symphony.properties for sending mail");
return;
}
} else {
if (StringUtils.isBlank(MailSender.username) || StringUtils.isBlank(MailSender.password)) {
LOGGER.warn("Please configure [#### Local Mail channel ####] section in symphony.properties for sending mail");
return;
}
}
Keys.fillServer(dataModel);
try {
final Map<String, Object> formData = new HashMap<>();
formData.put("apiUser", SENDCLOUD_BATCH_API_USER);
formData.put("apiKey", SENDCLOUD_BATCH_API_KEY);
formData.put("from", SENDCLOUD_BATCH_FROM);
formData.put("fromName", fromName);
formData.put("subject", subject);
formData.put("templateInvokeName", templateName);
final Template template = TEMPLATE_CFG.getTemplate(templateName + ".ftl");
final StringWriter stringWriter = new StringWriter();
template.process(dataModel, stringWriter);
stringWriter.close();
final String html = stringWriter.toString();
// Creates or updates the SendCloud email template
if ("sendcloud".equals(MAIL_CHANNEL)) {
refreshWeeklyTemplate(html);
}
int index = 0;
final int size = toMails.size();
List<String> batch = new ArrayList<>();
HttpResponse response;
while (index < size) {
final String mail = toMails.get(index);
batch.add(mail);
index++;
if (batch.size() > 99) {
if ("aliyun".equals(MAIL_CHANNEL)) {
final String toMail = getStringToMailByList(batch);
aliSendHtml(ALIYUN_BATCH_FROM, fromName, subject, toMail, html, ALIYUN_ACCESSKEY, ALIYUN_ACCESSSECRET);
LOGGER.info("Sent [" + batch.size() + "] mails");
} else if ("local".equals(MAIL_CHANNEL.toLowerCase())) {
MailSender.getInstance().sendHTML(fromName, subject, batch, html);
} else {
try {
final JSONObject xsmtpapi = new JSONObject();
xsmtpapi.put("to", batch);
xsmtpapi.put("sub", new JSONObject());
formData.put("xsmtpapi", xsmtpapi.toString());
response = HttpRequest.post("http://api.sendcloud.net/apiv2/mail/sendtemplate").form(formData).send();
LOGGER.debug(response.bodyText());
response.close();
LOGGER.info("Sent [" + batch.size() + "] mails");
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Send mail error", e);
}
}
batch.clear();
}
}
if (!batch.isEmpty()) { // Process remains
if ("aliyun".equals(MAIL_CHANNEL)) {
final String toMail = getStringToMailByList(batch);
aliSendHtml(ALIYUN_BATCH_FROM, fromName, subject, toMail, html, ALIYUN_ACCESSKEY, ALIYUN_ACCESSSECRET);
LOGGER.info("Sent [" + batch.size() + "] mails");
} else if ("local".equals(MAIL_CHANNEL.toLowerCase())) {
MailSender.getInstance().sendHTML(fromName, subject, batch, html);
} else {
try {
final JSONObject xsmtpapi = new JSONObject();
xsmtpapi.put("to", batch);
xsmtpapi.put("sub", new JSONObject());
formData.put("xsmtpapi", xsmtpapi.toString());
response = HttpRequest.post("http://api.sendcloud.net/apiv2/mail/sendtemplate").form(formData).send();
LOGGER.debug(response.bodyText());
response.close();
LOGGER.info("Sent [" + batch.size() + "] mails");
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Send mail error", e);
}
}
}
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Batch send mail error", e);
}
}
/**
* Sends a HTML mail via Aliyun.
*
* @param fromName the specified from name
* @param subject the specified subject
* @param toMail the specified receiver mail
* @param html send html
*/
private static void aliSendHtml(final String sendMail, final String fromName, final String subject, final String toMail,
final String html, final String accessKey, final String accessSecret) throws Exception {
final Map<String, Object> map = new HashMap<>();
map.put("Action", "SingleSendMail");
map.put("Format", "JSON");
map.put("Version", "2015-11-23");
map.put("AccessKeyId", accessKey);
map.put("SignatureMethod", "HMAC-SHA1");
map.put("Timestamp", getISO8601Time());
map.put("SignatureVersion", "1.0");
map.put("SignatureNonce", String.valueOf(System.currentTimeMillis()));
map.put("AccountName", sendMail);
map.put("FromAlias", fromName);
map.put("ReplyToAddress", "true");
map.put("AddressType", "1");
map.put("ToAddress", toMail);
map.put("Subject", subject);
map.put("HtmlBody", html);
final String[] sortedKeys = map.keySet().toArray(new String[]{});
Arrays.sort(sortedKeys);
final StringBuilder canonicalizedQueryString = new StringBuilder();
try {
for (String key : sortedKeys) {
canonicalizedQueryString.append("&")
.append(Mails.percentEncode(key)).append("=")
.append(Mails.percentEncode(map.get(key).toString()));
}
final StringBuffer stringToSign = new StringBuffer();
stringToSign.append("POST");
stringToSign.append("&");
stringToSign.append(Mails.percentEncode("/"));
stringToSign.append("&");
stringToSign.append(Mails.percentEncode(canonicalizedQueryString.toString().substring(1)));
map.put("Signature", HmacSHA1.signString(stringToSign.toString(), accessSecret + "&"));
} catch (UnsupportedEncodingException exp) {
throw new RuntimeException("UTF-8 encoding is not supported.");
}
final HttpResponse response = HttpRequest.post("https://dm.aliyuncs.com").form(map).send();
LOGGER.debug(response.bodyText());
response.close();
}
private static String percentEncode(final String value) throws UnsupportedEncodingException {
return value != null ? URLEncoder.encode(value, "UTF-8").replace("+", "%20")
.replace("*", "%2A").replace("%7E", "~") : null;
}
private static String getISO8601Time() {
final Date nowDate = new Date();
final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
df.setTimeZone(new SimpleTimeZone(0, "GMT"));
return df.format(nowDate);
}
private static String getStringToMailByList(final List<String> toMails) {
final StringBuffer mails = new StringBuffer();
for (String mail : toMails) {
mails.append(mail + ",");
}
mails.deleteCharAt(mails.length() - 1);
return mails.toString();
}
private static void refreshWeeklyTemplate(final String html) {
final Map<String, Object> addData = new HashMap<>();
addData.put("apiUser", SENDCLOUD_BATCH_API_USER);
addData.put("apiKey", SENDCLOUD_BATCH_API_KEY);
addData.put("invokeName", TEMPLATE_NAME_WEEKLY);
addData.put("name", "Weekly Newsletter");
addData.put("subject", "Weekly Newsletter");
addData.put("templateType", "1"); // 批量邮件
addData.put("html", html);
HttpRequest.post("http://api.sendcloud.net/apiv2/template/add").form(addData).send();
final Map<String, Object> updateData = new HashMap<>();
updateData.put("apiUser", SENDCLOUD_BATCH_API_USER);
updateData.put("apiKey", SENDCLOUD_BATCH_API_KEY);
updateData.put("invokeName", TEMPLATE_NAME_WEEKLY);
updateData.put("html", html);
HttpRequest.post("http://api.sendcloud.net/apiv2/template/update").form(updateData).send();
}
}
/**
* 通过 JavaMail SMTP 发送邮件.
* <p>
* 支持三种类型的邮件:
* <ul>
* <li>SIMPLE 简单类型,可以发送 HTML 格式文本,遵从 FreeMarker 模板的设置</li>
* <li>IMAGE HTML 格式类型,同时会保存 HTML 里面的 image 到磁盘,并生成 eml 保存到服务器的配置目录</li>
* <li>MULTI 带附件的 Attachment,TODO</li>
* </ul>
* </p>
*
* @author <a href="https://github.com/snowflake3721">snowflake</a>
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.1.1, Mar 29, 2017
* @since 2.1.0
*/
final class MailSender implements java.io.Serializable {
public static final String sender = Symphonys.get("mail.local.smtp.sender");
public static final String username = Symphonys.get("mail.local.smtp.username");
public static final String password = Symphonys.get("mail.local.smtp.passsword"); /* 换成自己的密码哦 */
private static final long serialVersionUID = -1000794424345267933L;
private static final String CHARSET = "text/html;charset=UTF-8";
private static final Logger LOGGER = Logger.getLogger(Markdowns.class);
private static final boolean is_debug = Boolean.valueOf(Symphonys.get("mail.local.isdebug"));
private static final String mail_transport_protocol = Symphonys.get("mail.local.transport.protocol");
private static final String mail_host = Symphonys.get("mail.local.host");
private static final String mail_port = Symphonys.get("mail.local.port");
private static final String mail_smtp_auth = Symphonys.get("mail.local.smtp.auth");
private static final String mail_smtp_ssl = Symphonys.get("mail.local.smtp.ssl");
private static final String saved_path = Symphonys.get("mail.local.saved.eml.path");
private static MailSender mailSender;
private static Properties prop = new Properties();
private MailSender() {
prop.setProperty("mail.transport.protocol", mail_transport_protocol);
prop.setProperty("mail.host", mail_host);
prop.setProperty("mail.port", mail_port);
prop.setProperty("mail.smtp.auth", mail_smtp_auth);
prop.setProperty("mail.smtp.ssl", mail_smtp_ssl);
prop.setProperty("mail.smtp.sender", sender);
prop.setProperty("mail.smtp.username", username);
prop.setProperty("mail.smtp.passsword", password);
}
public static final MailSender getInstance() {
if (null == mailSender) {
mailSender = MailSenderHolder.INSTANCE;
}
return mailSender;
}
private static Set<String> getImgStr(String htmlStr) {
Set<String> pics = new HashSet<>();
String img = "";
Pattern p_image;
Matcher m_image;
// String regEx_img = "<img.*src=(.*?)[^>]*?>"; //图片链接地址
String regEx_img = "<img.*src\\s*=\\s*(.*?)[^>]*?>";
p_image = Pattern.compile(regEx_img, Pattern.CASE_INSENSITIVE);
m_image = p_image.matcher(htmlStr);
while (m_image.find()) {
// 得到<img />数据
img = m_image.group();
// 匹配<img>中的src数据
Matcher m = Pattern.compile("src\\s*=\\s*\"?(.*?)(\"|>|\\s+)").matcher(img);
while (m.find()) {
pics.add(m.group(1));
}
}
return pics;
}
private static void setTo(String[] to, MimeMessage message) throws MessagingException, AddressException {
// 指明邮件的收件人,现在发件人和收件人是一样的,那就是自己给自己发
if (null != to && to.length > 0) {
if (to.length == 1) {
message.setRecipient(Message.RecipientType.TO, new InternetAddress(to[0]));
} else {
List<InternetAddress> iaList = new ArrayList<InternetAddress>();
for (String t : to) {
InternetAddress ia = new InternetAddress(t);
iaList.add(ia);
}
InternetAddress[] iaArray = new InternetAddress[to.length];
message.setRecipients(Message.RecipientType.TO, iaList.toArray(iaArray));
}
}
}
public static void main(String[] args) throws Exception {
System.out.println(CHARSET.toLowerCase());
/*
* MailSender mailSender = getInstance();
*
* String subject = "eml with Image"; String content =
* "这是一封邮件正文带图片<img width=\"60px\" src=\"http://localhost:8080/images/logo-M301-161X105.png\" />的邮件"
* ; String[] tos = { "bruceyang_it@163.com" };
* mailSender.sendMessage(tos, subject, content, saved_path,
* MailType.IMAGE);
*/
}
private Object readResolve() {
return MailSenderHolder.INSTANCE;
}
public void sendMessage(String[] tos, String subject, String content, String savedEmlPath, MailType mailType)
throws Exception {
// 1、创建session
Session session = Session.getInstance(prop);
// 开启Session的debug模式,这样就可以查看到程序发送Email的运行状态
session.setDebug(is_debug);
// 2、通过session得到transport对象
Transport ts = session.getTransport();
// 3、使用邮箱的用户名和密码连上邮件服务器,发送邮件时,发件人需要提交邮箱的用户名和密码给smtp服务器,用户名和密码都通过验证之后才能够正常发送邮件给收件人。
ts.connect(mail_host, username, password);
MimeMessage message = new MimeMessage(session);
// 4、创建邮件
// Message message = createSimpleMail(session);
if (MailType.SIMPLE.equals(mailType)) {
createTextMail(message, sender, tos, subject, content, savedEmlPath);
} else if (MailType.IMAGE.equals(mailType)) {
message = createImageMail(message, sender, tos, subject, content, savedEmlPath);
} else {
// TODO MULTI
createTextMail(message, sender, tos, subject, content, savedEmlPath);
}
// 5、发送邮件
ts.sendMessage(message, message.getAllRecipients());
LOGGER.debug(tos.toString());
LOGGER.debug(subject);
LOGGER.debug(content);
ts.close();
}
/**
* 创建一封只包含文本的邮件.
*
* @param message
* @param from
* @param to
* @param subject
* @param content
* @param savedEmlPathName
* @return
* @throws Exception
*/
public MimeMessage createTextMail(MimeMessage message, String from, String[] to, String subject, String content,
String savedEmlPathName) throws Exception {
long currentTime = System.currentTimeMillis();
if (!savedEmlPathName.endsWith("/")) {
savedEmlPathName = savedEmlPathName + "/";
}
// 构造日期目录
String datePath = buildDatePath();
String savedEmlPathNameDate = savedEmlPathName + datePath;
File savedEmlPathNameDateFile = new File(savedEmlPathNameDate);
if (!savedEmlPathNameDateFile.exists()) {
savedEmlPathNameDateFile.mkdirs();
}
// 构造存储文件绝对路径
String fileName = savedEmlPathNameDate + currentTime + ".eml";
// 指明邮件的发件人
message.setFrom(new InternetAddress(from));
setTo(to, message);
// 邮件的标题,只包含文本的简单邮件
if (StringUtils.isEmpty(subject)) {
subject = "email from the system";
}
message.setSubject(StringUtils.trimToEmpty(subject));
// 邮件的文本内容
message.setContent(content, CHARSET);
saveMessageFile(message, fileName);
// 返回创建好的邮件对象
return message;
}
/**
* 生成一封邮件正文带图片的邮件.
*
* @param message
* @param from
* @param to
* @param subject
* @param content
* @param savedEmlPath
* @return
* @throws Exception
*/
public MimeMessage createImageMail(MimeMessage message, String from, String[] to, String subject, String content,
String savedEmlPath) throws Exception {
// 创建邮件
// MimeMessage message = new MimeMessage(session);
// 设置邮件的基本信息
// 发件人
message.setFrom(new InternetAddress(from));
setTo(to, message);
// 邮件标题
if (StringUtils.isEmpty(subject)) {
subject = "Email from the system [Dromala special community for study]";
}
message.setSubject(StringUtils.trimToEmpty(subject));
// 准备邮件数据
message = resolveContentForImage(message, content, savedEmlPath);
// 返回创建好的邮件
return message;
}
public MimeMessage resolveContentForImage(MimeMessage message, String content, String savedEmlPathName)
throws Exception {
long currentTime = System.currentTimeMillis();
if (!savedEmlPathName.endsWith("/")) {
savedEmlPathName = savedEmlPathName + "/";
}
// 构造日期目录
String datePath = buildDatePath();
String savedEmlPathNameDate = savedEmlPathName + datePath;
File savedEmlPathNameDateFile = new File(savedEmlPathNameDate);
if (!savedEmlPathNameDateFile.exists()) {
savedEmlPathNameDateFile.mkdirs();
}
// 构造存储文件绝对路径
String fileName = savedEmlPathNameDate + currentTime + ".eml";
Set<String> imageStrSet = getImgStr(content);
// 准备邮件正文数据
MimeBodyPart text = new MimeBodyPart();
if (null != imageStrSet && imageStrSet.size() > 0) {
int i = 0;
for (String imageStr : imageStrSet) {
// 准备图片数据
MimeBodyPart image = new MimeBodyPart();
String imagenew = currentTime + "/" + i + imageStr.substring(imageStr.lastIndexOf("."));
// imagenew = imagenew.replaceAll("/", "_");
String savedPathAndFileName = savedEmlPathNameDate + imagenew;
DataHandler dh = new DataHandler(new UrlDataSource(imageStr, savedPathAndFileName, true));
image.setDataHandler(dh);
String imagenewcid = "cid:" + imagenew;
image.setContentID(imagenew);
// 描述数据关系
MimeMultipart mm = new MimeMultipart();
mm.addBodyPart(text);
mm.addBodyPart(image);
mm.setSubType("related");
message.setContent(mm);
content = content.replaceAll(imageStr, imagenewcid);
text.setContent(content, CHARSET);
message.saveChanges();
i++;
}
}
text.setContent(content, CHARSET);
saveMessageFile(message, fileName);
return message;
}
private void saveMessageFile(MimeMessage message, String fileName)
throws MessagingException, FileNotFoundException, IOException {
message.saveChanges();
// 将创建好的邮件写入到E盘以文件的形式进行保存
FileOutputStream fos = null;
try {
fos = new FileOutputStream(fileName);
message.writeTo(fos);
fos.flush();
} finally {
if (fos != null) {
fos.close();
}
}
}
private String buildDatePath() {
StringBuilder sb = new StringBuilder();
Calendar ca = Calendar.getInstance();
int year = ca.get(Calendar.YEAR);// 获取年份
int month = ca.get(Calendar.MONTH);// 获取月份
int day = ca.get(Calendar.DATE);// 获取日
sb.append(year).append("/").append(month).append("/").append(day).append("/");
return sb.toString();
}
/**
* Sends a HTML mail for toMailList.
*
* @param fromName
* @param subject
* @param toMailList
* @param html
*/
public void sendHTML(final String fromName, final String subject, final List<String> toMailList, String html) {
if (null != toMailList && toMailList.size() > 0) {
sendHTML(fromName, subject, toMailList.toArray(new String[toMailList.size()]), html);
}
}
/**
* Sends a HTML mail.
*
* @param fromName
* @param subject
* @param toMailSingle
* @param html
*/
public void sendHTML(final String fromName, final String subject, final String toMailSingle, String html) {
sendHTML(fromName, subject, new String[]{toMailSingle}, html);
}
public void sendHTML(final String fromName, final String subject, final String[] toMail, final String html) {
try {
/*
* Keys.fillServer(dataModel); Keys.fillRuntime(dataModel);
*
*
* final Template template = TEMPLATE_CFG.getTemplate(templateName +
* ".ftl"); final StringWriter stringWriter = new StringWriter();
* template.process(dataModel, stringWriter); stringWriter.close();
* final String content = stringWriter.toString();
*/
getInstance().sendMessage(toMail, subject, html, saved_path, MailType.IMAGE);
LOGGER.debug(html);
} catch (Exception e) {
LOGGER.log(Level.ERROR, "Send mail error", e);
}
}
public static enum MailType {
SIMPLE, IMAGE /* html with image */, MULTI/* Attachment TODO */
}
private static class MailSenderHolder {
private static final MailSender INSTANCE = new MailSender();
}
}
/**
* 加载网络资源图片保存到本地
*
* @author snowflake
* @version 1.0.0.0, Mar 9, 2016
* @since 2.0.0
*/
class UrlDataSource implements DataSource {
private String urlPath;
private String savedFileName;
private boolean saved;
private FileTypeMap typeMap = null;
private File _file;
public UrlDataSource(String urlPath, String savedFileName, boolean saved) {
this.urlPath = urlPath;
this.savedFileName = savedFileName;
this.saved = saved;
File imageFile = new File(this.savedFileName);
this._file = imageFile;
}
public static byte[] readInputStream(InputStream inStream) throws IOException {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
// 创建一个Buffer字符串
byte[] buffer = new byte[1024];
// 每次读取的字符串长度,如果为-1,代表全部读取完毕
int len = 0;
// 使用一个输入流从buffer里把数据读取出来
while ((len = inStream.read(buffer)) != -1) {
// 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
outStream.write(buffer, 0, len);
}
// 关闭输入流
inStream.close();
// 把outStream里的数据写入内存
return outStream.toByteArray();
}
@Override
public InputStream getInputStream() throws IOException {
return getInputStreamFromURL(this.urlPath, this.saved);
}
@Override
public OutputStream getOutputStream() throws IOException {
if (this._file.isDirectory()) {
if (!this._file.exists()) {
this._file.mkdirs();
}
}
String parentPath = this._file.getParent();
File _filePath = new File(parentPath);
_filePath.mkdirs();
return new FileOutputStream(this._file);
}
@Override
public String getContentType() {
// check to see if the type map is null?
if (typeMap == null)
return FileTypeMap.getDefaultFileTypeMap().getContentType(_file);
else
return typeMap.getContentType(_file);
}
@Override
public String getName() {
return _file.getName();
}
private InputStream getInputStreamFromURL(String urlPath, boolean saved) throws IOException {
// new一个URL对象
URL url = new URL(urlPath);
// 打开链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// 设置请求方式为"GET"
conn.setRequestMethod("GET");
// 超时响应时间为5秒
conn.setConnectTimeout(5 * 1000);
// 通过输入流获取图片数据
InputStream inStream = conn.getInputStream();
// 得到图片的二进制数据,以二进制封装得到数据,具有通用性
if (saved) {
try {
saveFile(inStream);
} catch (Exception e) {
e.printStackTrace();
}
}
InputStream fis = new FileInputStream(_file);
return fis;
}
// 得到图片的二进制数据,以二进制封装得到数据,具有通用性
public void saveFile(InputStream inStream) throws IOException {
byte[] data = readInputStream(inStream);
// new一个文件对象用来保存图片,默认保存当前工程根目录
// File imageFile = new File(fileName);
// 创建输出流
FileOutputStream outStream = (FileOutputStream) getOutputStream();
// 写入数据
outStream.write(data);
// 关闭输出流
outStream.close();
}
/**
* Return the File object that corresponds to this FileDataSource.
*
* @return the File object for the file represented by this object.
*/
public File getFile() {
return _file;
}
/**
* Set the FileTypeMap to use with this FileDataSource
*
* @param map The FileTypeMap for this object.
*/
public void setFileTypeMap(FileTypeMap map) {
typeMap = map;
}
}