使用JavaMail发送邮件-从FTP读取图片并添加到邮件正文发送
记录一下,使用JavaMail发送邮件。
业务分析
最近工作需要,需要从FTP读取图片内容,添加到邮件正文发送。发送邮件正文,添加附件采用Spring的MimeMessageHelper对象来完成,添加图片也将采用MimeMessageHelper来完成。
查看博客发现MimeMessageHelper有addInline API,里面包含三个参数contentId,InputStreamSource,content-type,以下是文档里的解释:
public void addInline(java.lang.String contentId,InputStreamSource inputStreamSource,java.lang.String contentType) throws MessagingException
Add an inline element to the MimeMessage, taking the content from an org.springframework.core.InputStreamResource, and specifying the content type explicitly.
You can determine the content type for any given filename via a Java Activation Framework's FileTypeMap, for example the one held by this helper.
Note that the InputStream returned by the InputStreamSource implementation needs to be a fresh one on each call, as JavaMail will invoke getInputStream() multiple times.
NOTE: Invoke addInline after setText; else, mail readers might not be able to resolve inline references correctly.
Parameters:
contentId - the content ID to use. Will end up as "Content-ID" header in the body part, surrounded by angle brackets: e.g. "myId" -> "<myId>". Can be referenced in HTML source via src="cid:myId" expressions.
inputStreamSource - the resource to take the content from
contentType - the content type to use for the element
Throws:
MessagingException - in case of errors
See Also:
setText(java.lang.String), getFileTypeMap(), addInline(String, org.springframework.core.io.Resource), addInline(String, javax.activation.DataSource)
百度翻译过来大概意思是:
contentId:要使用的ContentId。将在正文部分以“content id”标题结尾,并用尖括号包围:例如“myid”->“<myid>”。也可以通过src=“cid:myid”表达式应用在HTML源代码中。
inputStreamSource:需要传入的图片资源。
contentType:将会被元素使用的contentType,内容类型,一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定文件接收方将以什么形式、什么编码读取这个文件。
所以,contentId自己命名后,需要将这个id添加到<img src="cid:id">中被引,content-type在这里因为传输的是图片,需要选择image/jpeg,而inputStreamSource来源自ftp读取结果。
业务实现
接下主要问题是如何读取ftp里的图片信息,并将图片信息转换成inputStreamSource。因此分为两步来实现:
(1)连接ftp
参考代码,主要参考了博客https://www.cnblogs.com/l412382979/archive/2018/01/15/8288030.html,执行方法后,返回保存InputStream对象和FTPClient对象的Map,给下一步使用。
/**
* Name:get InputStream from ftp
* @author yangchaolin
*/
public static Map<String,Object> getDefectImageFromFtpForACCM(String sectionName) throws Exception{
InputStream is=null;
FTPClient ftpClient=new FTPClient();
Map<String,Object> map=new HashMap<String,Object>();
try{
//创建连接
ftpClient.connect("ftp地址",端口号);
ftpClient.login("用户名", "密码");
//验证用户名和密码
int reply=ftpClient.getReplyCode();
if(!FTPReply.isPositiveCompletion(reply)){
log.info("连接ftp失败,用户名或密码错误!");
ftpClient.disconnect();
}else{
log.info("连接ftp成功!");
}
}catch(SocketException e){
log.info("ftp IP地址可能错误");
throw new CustomException("ftp IP地址可能错误!");
}catch(IOException e){
log.info("ftp 端口错误");
throw new CustomException("ftp 端口错误!");
} try{
ftpClient.setDataTimeout(60000);
ftpClient.setConnectTimeout(60000);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.setControlEncoding("UTF-8");//支持中文
ftpClient.setBufferSize(8*1024);
//获取指定文件的InputStream
ftpClient.changeWorkingDirectory("文件目录");//目录最前面不能以'/'开头,否则会读不到内容
is=ftpClient.retrieveFileStream(sectionName);
}catch(FileNotFoundException e){
log.info("没有找到文件");
throw new CustomException("没有找到文件");
}catch(SocketException e){
log.info("连接ftp失败");
throw new CustomException("连接ftp失败");
}catch(IOException e){
log.info("文件读取错误");
throw new CustomException("文件读取错误");
}
map.put("inputStream", is);
map.put("ftpClient", ftpClient);
return map;
}
这里截取了部分代码,先将InputStream转换成字节数组,然后将字节数组作为参数传入方法ByteArrayResource()中,得到InputeStreamSource对象,InputeStreamSource对象将传入MimeMessageHelper对象中,作为添加邮件中图片使用。
//读取ftp上图片内容
try {
Map<String,Object> map=getDefectImageFromFtpForACCM("Mountain.jpg");
InputStream isOfImage=(InputStream) map.get("inputStream");
FTPClient ftpClient=(FTPClient) map.get("ftpClient");
if(isOfImage!=null){
byte[] bytes=IOUtils.toByteArray(isOfImage);//将图片输入流转化为字节数组
//isOfImage.read(bytes);
issOfImage=new ByteArrayResource(bytes);
log.info("图片byte数组大小为:"+bytes.length);
//将inputStream关闭后才能执行completePendingCommand方法
isOfImage.close();
ftpClient.completePendingCommand();
ftpClient.disconnect();
}
} catch (Exception e1) {
throw new CustomException("读取ftp图片失败!");
}
(3)将InputStreamSource传入MimeMessageHelper中发送带图片的邮件,图片显示在正文中
这里截取了部分代码,helper就是MimeMessageHelper对象,其中defectImage就是contentId,将会用在<img src="cid:defectImage">标签中,相当如一个标识符(html邮件部分代码不做展示),通过它可以找到图片资源。content-type暂时定义为image/jepg,这个需要参考具体的标准表,因为本次测试使用的是jpg格式图片,所以选择它。
//------------------------------测试用
helper.setText(message.toString(),true);//HTML邮件
//image就是InputStreamSource对象
helper.addInline("defectImage", image, "image/jpeg"); //content-type暂定义为image/jpeg,代表将已图片解码
log.info("邮件内容为:"+message.toString());
//------------------------------测试用
邮件发送效果

总结
在添加邮件到邮件正文的过程中,发生了如下问题:
(1)图片只发送了一部分,没有全部发送完成。查看原因发现是代码inputStream转化成byte[]数组时,长度出现了问题,导致只传输了部分图片,使用IOUtils.toByteArray() API后,长度正常。
(2)图片在foxmail显示正常,但是在chrome浏览器显示不出图片,查看发现content-type设置为"text/html",将其修改为"image/jpeg"后显示正常。
(3)执行InputStream流关闭后,执行completePendingCommand()方法出错,发现是先关闭了ftp的连接,导致无法执行。completePendingCommand()会等FTPClient返回226 Transfer complete,但是FTPClient只有在接受到InputStream执行close方法时,才会返回。所以先要执行InputStream的close方法,再执行completePendingCommand,最后再关闭ftp连接。参考自:https://ask.csdn.net/questions/166657
使用JavaMail发送邮件-从FTP读取图片并添加到邮件正文发送的更多相关文章
- 使用JavaMail发送邮件(含文本/附件/图片)的工具类
		
记录利用公司内搭建的smtp邮件服务器,使用javax mail发送邮件的程序 package com.test.mailTest; import java.util.Date; import jav ...
 - ftp读取图片并转Base64
		
public String download(String ftpUrl,String sfzh){ FTPClient ftpClient = new FTPClient(); InputStrea ...
 - 将PPT文件内容转换为图片放在Email邮件正文中发送
		
通过Email推送统计报告.一般除了要求将PPT报告文件作为附件发给用户,同时希望将报告内容在邮件中直观展示. 一份统计报告中经常包含柱状图.饼图.好看的图表,这些信息要直接在Email中展示比较复杂 ...
 - Spring  JavaMail发送邮件
		
JavaMail的介绍 JavaMail,顾名思义,提供给开发者处理电子邮件相关的编程接口.它是Sun发布的用来处理email的API.它可以方便地执行一些常用的邮件传输. 虽然JavaMail是 ...
 - JavaMail发送邮件(超详细)
		
一:邮件发送的基本概念 本文我将阐述使用JavaMail方式发送和接收Email的详细说明,本博客本着以后遇到类似的邮件发送需求可以直接把代码粘过去直接使用,快捷方便省时间,对于刚接触的JavaMai ...
 - JavaMail发送邮件
		
发送邮件包含的内容有: from字段 --用于指明发件人 to字段 --用于指明收件人 subject字段 --用于说明邮件主题 cc字段 -- 抄送,将邮件发送给收件人的同时抄 ...
 - JavaMail发送邮件第一版
		
首先,我们先来了解一个基本的知识点,用什么工具来发邮件? 简单的说一下,目前用的比较多的客户端:OutLook,Foxmail等 顺便了解一下POP3.SMTP协议的区别: POP3,全名为" ...
 - 使用JavaMail发送邮件-no object DCH for MIME type multipart/mixed报错解决
		
最近需要实现一个使用Spring schedule按一定时间间隔自动触发条件发送邮件的功能,在开发的过程中,是按照先测试能发出text/html文本邮件,然后测试添加附件发送邮件,我碰到的问题是,文本 ...
 - 利用JavaMail发送邮件:smtp.163.com
		
一.利用JavaMail发送邮件案例: 1.maven项目结构: 2.先在pom.xml里边加入Javamail依赖,系统会根据坐标自动下载mail包(前提是配置好了maven): 3.配置email ...
 
随机推荐
- 2018.4.25  github创建新项目
			
echo "# IntegrateDemo" >> README.md git init git add README.md git commit -m "f ...
 - [JLOI2011]不重复数字
			
原题链接 题解 题目大意:给出N个数,要求把其中重复的去掉,只保留第一次出现的数.最后按顺序输出N <= 50000 然这题是个哈希的典型题目 HASH,我对于它的理解就是一个桶%一个数,当然并 ...
 - 在linux系统下运行jar包的命令如下
			
1.java -jar xxxxx.jar // 当前ssh窗口被锁定,可按CTRL + C打断程序运行,或直接关闭窗口,程序退出 2.java -jar xxxxx.jar & //当 ...
 - LG1912 [NOI2009]诗人小G
			
题意 题目描述 小G是一个出色的诗人,经常作诗自娱自乐.但是,他一直被一件事情所困扰,那就是诗的排版问题. 一首诗包含了若干个句子,对于一些连续的短句,可以将它们用空格隔开并放在一行中,注意一行中可以 ...
 - PythonStudy——机器语言 Machine Language
			
编程语言 编程语言(programming language),是用来定义计算机程序的形式语言.它是一种被标准化的交流技巧,用来向计算机发出指令.一种计算机语言让程序员能够准确地定义计算机所需要使用的 ...
 - Web前端新手想提升自身岗位竞争力,需做好这3件事!
			
Web前端开发行业的发展前景毋庸置疑,只要是互联网企业,几乎都需要Web前端开发工程师.虽然Web前端入行门槛低,但竞争逐渐激烈,想要取得高薪,就一定要具备强大的实力.那么,在重庆Web前端培训学习中 ...
 - 记一次php脚本memory exhausted
			
表象报错如下: Error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 16651985 bytes) 出 ...
 - 1.1.21 Word修改文章目录
			
1.选中目录后,右键[编辑域],选择[索引和目录].选择[TOC],点击右侧的[目录]. 2.选中[目录]后,按照如下[1][2][3]顺序,按格式要求修改目录即可.
 - 2.1 Visio画图后,粘贴到word白边太宽
			
如下图所示:Visio2007画图后,图白边距很宽. 右击打开>将鼠标移动到画布边缘,按下Ctrl后鼠标变为双箭头,然后拖拽方格画布,拖拽合适的宽度保存即可.
 - json转对象,奇怪的映射
			
偶然看见此代码,记录下,将来可能会用到. ObjectMapper objectMapper = new ObjectMapper(); if (StringUtils.isNotEmpty(vari ...