mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
support image
This commit is contained in:
parent
b791a75dd6
commit
8a5efb84da
@ -7,7 +7,7 @@
|
||||
|
||||
### 新特性
|
||||
* 【core】 改进CollUtil.zip逻辑,减少内存复制(issue#I10T01@Gitee)
|
||||
* 【extra】 邮件支持图片(pr#495@Github)
|
||||
* 【extra】 邮件增加图片支持(pr#495@Github)
|
||||
|
||||
### Bug修复
|
||||
* 【http】 修复HttpRquest中body方法长度计算问题(issue#I10UPG@Gitee)
|
||||
|
@ -5,13 +5,12 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.DataSource;
|
||||
import javax.activation.FileDataSource;
|
||||
import javax.activation.FileTypeMap;
|
||||
import javax.mail.Authenticator;
|
||||
import javax.mail.BodyPart;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Session;
|
||||
@ -21,8 +20,11 @@ import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeMultipart;
|
||||
import javax.mail.util.ByteArrayDataSource;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
@ -49,10 +51,8 @@ public class Mail {
|
||||
private String content;
|
||||
/** 是否为HTML */
|
||||
private boolean isHtml;
|
||||
/** 附件列表 */
|
||||
private DataSource[] attachments;
|
||||
/** 图片列表 */
|
||||
private Map<String, InputStream> imageMap;
|
||||
/** 正文、附件和图片的混合部分 */
|
||||
private Multipart multipart = new MimeMultipart();
|
||||
/** 是否使用全局会话,默认为false */
|
||||
private boolean useGlobalSession = false;
|
||||
|
||||
@ -165,7 +165,8 @@ public class Mail {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置正文
|
||||
* 设置正文<br>
|
||||
* 正文可以是普通文本也可以是HTML(默认普通文本),可以通过调用{@link #setHtml(boolean)} 设置是否为HTML
|
||||
*
|
||||
* @param content 正文
|
||||
* @return this
|
||||
@ -185,9 +186,21 @@ public class Mail {
|
||||
this.isHtml = isHtml;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置正文
|
||||
*
|
||||
* @param content 正文内容
|
||||
* @param isHtml 是否为HTML
|
||||
* @return this
|
||||
*/
|
||||
public Mail setContent(String content, boolean isHtml) {
|
||||
setContent(content);
|
||||
return setHtml(isHtml);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文件类型附件
|
||||
* 设置文件类型附件,文件可以是图片文件,此时自动设置cid(正文中引用图片),默认cid为文件名
|
||||
*
|
||||
* @param files 附件文件列表
|
||||
* @return this
|
||||
@ -205,7 +218,7 @@ public class Mail {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置附件,附件使用{@link DataSource} 形式表示,可以使用{@link FileDataSource}包装文件表示文件附件
|
||||
* 增加附件或图片,附件使用{@link DataSource} 形式表示,可以使用{@link FileDataSource}包装文件表示文件附件
|
||||
*
|
||||
* @param attachments 附件列表
|
||||
* @return this
|
||||
@ -213,21 +226,74 @@ public class Mail {
|
||||
*/
|
||||
public Mail setAttachments(DataSource... attachments) {
|
||||
if (ArrayUtil.isNotEmpty(attachments)) {
|
||||
this.attachments = attachments;
|
||||
final Charset charset = this.mailAccount.getCharset();
|
||||
MimeBodyPart bodyPart;
|
||||
String nameEncoded;
|
||||
try {
|
||||
for (DataSource attachment : attachments) {
|
||||
bodyPart = new MimeBodyPart();
|
||||
bodyPart.setDataHandler(new DataHandler(attachment));
|
||||
nameEncoded = InternalMailUtil.encodeText(attachment.getName(), charset);
|
||||
// 普通附件文件名
|
||||
bodyPart.setFileName(nameEncoded);
|
||||
if(StrUtil.startWith(attachment.getContentType(), "image/")) {
|
||||
// 图片附件,用于正文中引用图片
|
||||
bodyPart.setContentID(nameEncoded);
|
||||
}
|
||||
this.multipart.addBodyPart(bodyPart);
|
||||
}
|
||||
} catch (MessagingException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加图片,图片的键对应到邮件模板中的占位字符串,图片类型默认为"image/jpeg"
|
||||
*
|
||||
* @param cid 图片与占位符,占位符格式为cid:${cid}
|
||||
* @param imageStream 图片文件
|
||||
* @since 4.6.3
|
||||
*/
|
||||
public Mail addImage(String cid, InputStream imageStream) {
|
||||
return addImage(cid, imageStream, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加图片,图片的键对应到邮件模板中的占位字符串
|
||||
*
|
||||
* @param cid 图片与占位符,占位符格式为cid:${cid}
|
||||
* @param imageStream 图片流,不关闭
|
||||
* @param contentType 图片类型,null赋值默认的"image/jpeg"
|
||||
* @since 4.6.3
|
||||
*/
|
||||
public Mail addImage(String cid, InputStream imageStream, String contentType) {
|
||||
ByteArrayDataSource imgSource;
|
||||
try {
|
||||
imgSource = new ByteArrayDataSource(imageStream, ObjectUtil.defaultIfNull(contentType, "image/jpeg"));
|
||||
} catch (IOException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
imgSource.setName(cid);
|
||||
return setAttachments(imgSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置图片,图片的键对应到邮件模板中的占位字符串
|
||||
* 增加图片,图片的键对应到邮件模板中的占位字符串
|
||||
*
|
||||
* @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
|
||||
* @param cid 图片与占位符,占位符格式为cid:${cid}
|
||||
* @param imageFile 图片文件
|
||||
* @since 4.6.3
|
||||
*/
|
||||
public Mail setImageMap(Map<String, InputStream> imageMap) {
|
||||
if (imageMap != null && imageMap.size() > 0) {
|
||||
this.imageMap = imageMap;
|
||||
public Mail addImage(String cid, File imageFile) {
|
||||
InputStream in = null;
|
||||
try{
|
||||
in = FileUtil.getInputStream(imageFile);
|
||||
return addImage(cid, in, FileTypeMap.getDefaultFileTypeMap().getContentType(imageFile));
|
||||
} finally {
|
||||
IoUtil.close(in);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,43 +396,12 @@ public class Mail {
|
||||
* @throws MessagingException 消息异常
|
||||
*/
|
||||
private Multipart buildContent(Charset charset) throws MessagingException {
|
||||
final Multipart mainPart = new MimeMultipart();
|
||||
|
||||
// 正文
|
||||
final BodyPart body = new MimeBodyPart();
|
||||
final MimeBodyPart body = new MimeBodyPart();
|
||||
body.setContent(content, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charset));
|
||||
mainPart.addBodyPart(body);
|
||||
this.multipart.addBodyPart(body);
|
||||
|
||||
// 附件
|
||||
if (ArrayUtil.isNotEmpty(this.attachments)) {
|
||||
BodyPart bodyPart;
|
||||
for (DataSource attachment : attachments) {
|
||||
bodyPart = new MimeBodyPart();
|
||||
bodyPart.setDataHandler(new DataHandler(attachment));
|
||||
bodyPart.setFileName(InternalMailUtil.encodeText(attachment.getName(), charset));
|
||||
mainPart.addBodyPart(bodyPart);
|
||||
}
|
||||
}
|
||||
|
||||
// 图片
|
||||
for (Map.Entry<String, InputStream> entry : imageMap.entrySet()) {
|
||||
MimeBodyPart imgBodyPart = new MimeBodyPart();
|
||||
DataSource ds;
|
||||
try {
|
||||
ds = new ByteArrayDataSource(entry.getValue(), "image/jpeg");
|
||||
IoUtil.close(entry.getValue());
|
||||
} catch (IOException e) {
|
||||
throw new MailException(e);
|
||||
}
|
||||
|
||||
imgBodyPart.setDataHandler(new DataHandler(ds));
|
||||
// imgBodyPart.setHeader("Content-ID", String.format("<%s>", entry.getKey()));
|
||||
imgBodyPart.setContentID(entry.getKey());
|
||||
// add it
|
||||
mainPart.addBodyPart(imgBodyPart);
|
||||
}
|
||||
|
||||
return mainPart;
|
||||
return this.multipart;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,8 +5,11 @@ import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
@ -129,7 +132,7 @@ public class MailUtil {
|
||||
send(GlobalMailAccount.INSTANCE.getAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
|
||||
// ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
|
||||
/**
|
||||
* 发送邮件给多人
|
||||
*
|
||||
@ -175,7 +178,7 @@ public class MailUtil {
|
||||
public static void send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
|
||||
send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人<br>
|
||||
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
@ -205,7 +208,7 @@ public class MailUtil {
|
||||
public static void send(String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
|
||||
send(splitAddress(to), subject, content, imageMap, isHtml, files);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
|
||||
* 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
@ -223,7 +226,7 @@ public class MailUtil {
|
||||
public static void send(String to, String cc, String bcc, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
|
||||
send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的账户发送HTML邮件,发送给多人
|
||||
*
|
||||
@ -251,7 +254,7 @@ public class MailUtil {
|
||||
public static void send(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
|
||||
send(tos, null, null, subject, content, imageMap, isHtml, files);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的账户发送邮件,发送给多人
|
||||
*
|
||||
@ -268,8 +271,8 @@ public class MailUtil {
|
||||
public static void send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
|
||||
send(GlobalMailAccount.INSTANCE.getAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
|
||||
/**
|
||||
* 发送邮件给多人
|
||||
*
|
||||
@ -296,11 +299,12 @@ public class MailUtil {
|
||||
* @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
|
||||
* @param isHtml 是否为HTML格式
|
||||
* @param files 附件列表
|
||||
* @since 4.6.3
|
||||
*/
|
||||
public static void send(MailAccount mailAccount, Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
|
||||
send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送邮件给多人
|
||||
*
|
||||
@ -313,13 +317,14 @@ public class MailUtil {
|
||||
* @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
|
||||
* @param isHtml 是否为HTML格式
|
||||
* @param files 附件列表
|
||||
* @since 4.0.3
|
||||
* @since 4.6.3
|
||||
*/
|
||||
public static void send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
|
||||
public static void send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap,
|
||||
boolean isHtml, File... files) {
|
||||
send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------ Private method start
|
||||
|
||||
// ------------------------------------------------------------------------------------------------------------------------ Private method start
|
||||
/**
|
||||
* 发送邮件给多人
|
||||
*
|
||||
@ -330,53 +335,62 @@ public class MailUtil {
|
||||
* @param bccs 密送人列表,可以为null或空
|
||||
* @param subject 标题
|
||||
* @param content 正文
|
||||
* @param imageMap 图片与占位符,占位符格式为cid:$IMAGE_PLACEHOLDER
|
||||
* @param imageMap 图片与占位符,占位符格式为cid:${cid}
|
||||
* @param isHtml 是否为HTML格式
|
||||
* @param files 附件列表
|
||||
* @since 4.0.3
|
||||
* @since 4.6.3
|
||||
*/
|
||||
private static void send(MailAccount mailAccount, boolean useGlobalSession, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
|
||||
private static void send(MailAccount mailAccount, boolean useGlobalSession, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content,
|
||||
Map<String, InputStream> imageMap, boolean isHtml, File... files) {
|
||||
final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession);
|
||||
|
||||
//可选抄送人
|
||||
if(CollUtil.isNotEmpty(ccs)) {
|
||||
|
||||
// 可选抄送人
|
||||
if (CollUtil.isNotEmpty(ccs)) {
|
||||
mail.setCcs(ccs.toArray(new String[ccs.size()]));
|
||||
}
|
||||
//可选密送人
|
||||
if(CollUtil.isNotEmpty(bccs)) {
|
||||
// 可选密送人
|
||||
if (CollUtil.isNotEmpty(bccs)) {
|
||||
mail.setBccs(bccs.toArray(new String[bccs.size()]));
|
||||
}
|
||||
|
||||
|
||||
mail.setTos(tos.toArray(new String[tos.size()]));
|
||||
mail.setTitle(subject);
|
||||
mail.setContent(content);
|
||||
mail.setHtml(isHtml);
|
||||
mail.setFiles(files);
|
||||
mail.setImageMap(imageMap);
|
||||
|
||||
// 图片
|
||||
if(MapUtil.isNotEmpty(imageMap)) {
|
||||
for (Entry<String, InputStream> entry : imageMap.entrySet()) {
|
||||
mail.addImage(entry.getKey(), entry.getValue());
|
||||
// 关闭流
|
||||
IoUtil.close(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
mail.send();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将多个联系人转为列表,分隔符为逗号或者分号
|
||||
*
|
||||
* @param addresses 多个联系人,如果为空返回null
|
||||
* @return 联系人列表
|
||||
*/
|
||||
private static List<String> splitAddress(String addresses){
|
||||
if(StrUtil.isBlank(addresses)) {
|
||||
private static List<String> splitAddress(String addresses) {
|
||||
if (StrUtil.isBlank(addresses)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
List<String> result;
|
||||
if(StrUtil.contains(addresses, ',')) {
|
||||
if (StrUtil.contains(addresses, ',')) {
|
||||
result = StrUtil.splitTrim(addresses, ',');
|
||||
}else if(StrUtil.contains(addresses, ';')) {
|
||||
} else if (StrUtil.contains(addresses, ';')) {
|
||||
result = StrUtil.splitTrim(addresses, ';');
|
||||
}else {
|
||||
} else {
|
||||
result = CollUtil.newArrayList(addresses);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------ Private method end
|
||||
// ------------------------------------------------------------------------------------------------------------------------ Private method end
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package cn.hutool.extra.mail;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.junit.Assert;
|
||||
@ -17,17 +20,25 @@ public class MailTest {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void sendTest() {
|
||||
public void sendWithFileTest() {
|
||||
MailUtil.send("hutool@foxmail.com", "测试", "<h1>邮件来自Hutool测试</h1>", true, FileUtil.file("d:/测试附件文本.txt"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void sendTest2() {
|
||||
public void sendWithLongNameFileTest() {
|
||||
//附件名长度大于60时的测试
|
||||
MailUtil.send("hutool@foxmail.com", "测试", "<h1>邮件来自Hutool测试</h1>", true, FileUtil.file("d:/6-LongLong一阶段平台建设周报2018.3.12-3.16.xlsx"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void sendWithImageTest() {
|
||||
Map<String, InputStream> map = new HashMap<>();
|
||||
map.put("testImage", FileUtil.getInputStream("f:/test/me.png"));
|
||||
MailUtil.sendHtml("hutool@foxmail.com", "测试", "<h1>邮件来自Hutool测试</h1><img src=\"cid:testImage\" />", map);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void sendHtmlTest() {
|
||||
|
Loading…
Reference in New Issue
Block a user