写一个邮件发送大概有多麻烦
首先是初始化邮件工具类,初始化主要是创建一个邮件的会话,并获取该会话的mimeMessage对象。除此之外就是设置一些参数包括发件服务器,发件人账号密码等。
设置发件人信息,设置发件人通过mimeMessage对象的setFrom设置,它接收一个InternetAddress对象。如:”InternetAddress from = new InternetAddress(sender_username)
”
设置收件人信息,设置收件人通过mimeMessage对象的setRecipient方法,它可以接受两个参数,一个指定收件类型,一个指定收件人信息,该信息也必须是InternetAddress对象。
设置邮件主题,通过setSubject指定。
添加正文和附件,通过new mimeMultipart()
来实例化一个Multipart对象,邮件的所有实体都被添加至该对象。
添加正文,先实例化一个BodyPart对象,通过new MimeBodyPart()生成,调用bodyPart的setContent来设置正文,需要强调的是"text/html;charset=UTF-8"
这个不能少,指明发过去的邮件类型和编码格式。设置完毕后添加到Multipart对象中。
添加附件,大概最复杂的部分就是添加附件了。
首先是获取附件的File对象,通过File对象生成DataSource对象,通过DataSource对象生成DataHandler对象,调用BodyPart对象的setDataHandler方法将DataHandler对象传递进去,最后还要把BodyPart对象放进Multipart对象中。
把设置好的Multipart对象放进message对象中,通过setContent方法,最后一定一定千万要记得saveChanges。
最后的最后,创建一个实例,它相当于一个邮箱,如:transport = session.getTransport("smtp")
这里指定邮箱服务器为SMTP,然后验证它是否可用,通过connect方法验证。
最后的最后的最后就是发送邮件了,transport.sendMessage(message, message.getAllRecipients())
。
高端名词的低端解释
什么是mimeMessage?
在知道这个之前,我们需要先知道什么是MIME。MIME在中国被叫做多用途互联网邮件拓展,为什么会有MIME呢?这是因为旧邮件标准是不允许传输7位ASSIC码以外的邮件,因此创造了MIME的生存空间。而mimeMessage表示MIME样式的电子邮件,想要创建新的MIME样式消息的客户端将实例化一个空的MimeMessage对象,然后用适当的属性和内容填充它。在创建空的MEMI消息时必须在Property中添加如下参数:
properties.put("mail.smtp.auth", "true")
,据说只有指定mail.smtp.auth字段为TRUE才能通过验证。
什么是InternetAddress?
此类表示使用RFC822语法的Internet电子邮件地址。说白了就是专门用来表示电子邮件地址的。至于为什么这样表示,涉及到比较复杂的加密算法,大概是为了安全,大概是为了其他的什么,只是为了发一封邮件的我这里不追究。
什么是Multipart对象?
这个具体要看回MIME的概述了。之前说过MIME存在的意义是扩展旧邮件标准的不足,就是不能发送ASSIC以外的讯息。而在MIME支持的类型里面就有一种称为Multipart,它的用途是用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据。说白了就类似我们的Map一样的东西。
下面是MIME支持的类型和子类型(来自维基)
type有下面的形式。
- Text:用于标准化地表示的文本信息,文本消息可以是多种字符集和或者多种格式的;
- Multipart:用于连接消息体的多个部分构成一个消息,这些部分可以是不同类型的数据;
- Application:用于传输应用程序数据或者二进制数据;
- Message:用于包装一个E-mail消息;
- Image:用于传输静态图片数据;
- Audio:用于传输音频或者音声数据;
- Video:用于传输动态影像数据,可以是与音频编辑在一起的视频数据格式。
subtype用于指定type的详细形式。content-type/subtype配对的集合和与此相关的参数,将随着时间而增长。为了确保这些值在一个有序而且公开的状态下开发,MIME使用Internet Assigned Numbers –
- Authority (IANA)作为中心的注册机制来管理这些值。常用的subtype值如下所示:
- text/plain(纯文本)
- text/html(HTML文档)
- application/xhtml+xml(XHTML文档)
- image/gif(GIF图像)
- image/jpeg(JPEG图像)【PHP中为:image/pjpeg】
- image/png(PNG图像)【PHP中为:image/x-png】
- video/mpeg(MPEG动画)
- application/octet-stream(任意的二进制数据)
- application/pdf(PDF文档)
- application/msword(Microsoft Word文件)
- application/vnd.wap.xhtml+xml (wap1.0+)
- application/xhtml+xml (wap2.0+)
- message/rfc822(RFC 822形式)
- multipart/alternative(HTML邮件的HTML形式和纯文本形式,相同内容使用不同形式表示
- application/x-www-form-urlencoded(使用HTTP的POST方法提交的表单)
- multipart/form-data(同上,但主要用于表单提交时伴随文件上传的场合)
在应用场景,邮件是怎么传递附件的呢?这一点我做过很多尝试,qq上的附件肯定不是直接从本地获取附件,它至少是缓存了附件或是将附件上传到服务器上。对于客户端缓存附件这个我不是很了解,于是这里我们假设场景为发送附件时,将附件上传至服务器,之后从服务器中获取附件添加至邮件的Multipart中。那么在发送邮件之前我们要实现上传的工具类。上传比较简单,核心语句就是transferTo(转存),将获取到的MultipartFile对象转存到另一实际存在的路径/文件名(一般是加密后的文件名)中。这里不赘述。
public static String upload(MultipartFile file, String path){
String filename = file.getOriginalName();
UUID uuid = UUID.randomUUID();
String temp = filename.substring(0, filename.lastIndexOf("."));
String retFilename = "" + filename.replace(temp, uuid.toString());//uuid代替文件名
File target = new File(path, retFilename);//构造目标文件
if(!File.exist(target)){
File.mkdir()
}
file.transferTo(target);//转存数据到目标文件
return retFilename;//返回加密后的文件名
}
上面是上传的一个示例,记住!这些代码是在Spring框架下执行的,MultipartFile是Spring框架下一个临时存储文件的接口。所以在编写代码的时候先搭个Spring框架吧。不过这不是我关心的内容,既然上传完成了,那么继续编写邮件类吧。
编写邮件类的我们有时候会通过xml配置来配置发件人发件服务器等信息,这里我们只通过Java进行配置,而不经过xml。
首先思考我们大概需要些什么信息,然后把一些必要的东西封装进对象,这样会让我们的发邮件的方法签名更加简洁好看。
然后看代码吧。。。不知道怎么编了。。。
public class MailUtils {
private MimeMessage message;
private Session session;
private Properties properties = new Properties();
private Transport transport;
private String mailhost;
private String senderAccount;
private String senderPassword;
public void init(TEmailSetting email, boolean debug){
this.mailhost = email.getSendServer();
this.senderAccount = email.getAccount();
this.senderPassword = email.getPassword();
properties.put("mail.smtp.auth", "true");
session = Session.getInstance(properties);
session.setDebug(debug);
message = new MimeMessage(session);
}
public String sendMail(String subject, String htmlContent,
String[] receives, List<TAnnex> annexs, TEmailSetting email) throws MessagingException, UnsupportedEncodingException{
this.init(email, true);
//设置发件人
InternetAddress from = new InternetAddress(senderAccount);
message.setFrom(from);
//设置收件人
for(String receive : receives){
InternetAddress to = new InternetAddress(receive);
message.addRecipient(RecipientType.TO, to);
}
//设置邮件主题
message.setSubject(subject);
//设置正文附件混合的对象
Multipart multipart = new MimeMultipart();
//设置邮件正文
BodyPart contentPart = new MimeBodyPart();
contentPart.setContent(htmlContent, "text/html;charset=UTF-8");
multipart.addBodyPart(contentPart);
//设置附件
for(TAnnex annex : annexs){
File file = new File(annex.getAnnexUrl(), annex.getEncryptName());
if(file.exists()){
BodyPart annexPart = new MimeBodyPart();
DataSource source = new FileDataSource(file);
DataHandler dh = new DataHandler(source);
annexPart.setDataHandler(dh);
annexPart.setFileName(MimeUtility.encodeWord(annex.getOriginalName()));
multipart.addBodyPart(annexPart);
}
}
message.setContent(multipart);
//保存邮件
message.saveChanges();
//实例化发送实体
transport = session.getTransport("smtp");
//创建和邮件服务器的连接
transport.connect(mailhost, senderAccount, senderPassword);
//发邮件
transport.sendMessage(message, message.getAllRecipients());
//关闭连接,这里我不知道不关闭会怎样,但是我看到这种都是习惯性的关闭的
transport.close();
return "success";
}
}
这里引用一下某大神对发邮件的过程的解释。发邮件的具体过程如下:
所以大概就是这样,那个邮件类是根据我需求写的,因为公司的邮件工具不符合场景,所以自己写了一个。所以有看不懂的地方就算了吧。虽然说得真的有人看一样。。。
看着大神图片然后看代码其实异常简单,我们不过是创造了三个对象session对象,message对象,transport对象,然后连接transport和SMTP服务器,然后发送message到SMTP服务器,而怎么构造一个message对象呢?这其实就是模拟了我们写邮件的过程,最后发送!结束!