java 发送邮件 详解
来源:互联网 发布:诺基亚n1淘宝闪退 编辑:程序博客网 时间:2024/06/10 17:48
常见的邮件协议包括 :
SMTP : 简单邮件传输协议,用于发送电子邮件的传输协议
POP3 : 用于接收电子邮件的标准协议
IMAP : 互联网消息访问协议,是 POP3 的替代协议
这三种协议都有对应 SSL 加密传输的协议,分别是 SMTPS、 POP3S 和 IMAPS
JavaMail 体系结构
除 JavaMail 的核心包之外, JavaMail 还需要 JAF( JavaBeans Activation Framework)来处理不是纯文本的邮件内容。这包括 MIME(多用途互联网邮件扩展)、 URL 页面和文件附件等内容
JavaMail 是由 Sun 定义的一套收发电子邮件的 API,不同的厂商可以提供自己的实现类。但它并没有包含在 JDK 中,而是作为 Java EE 的一部分。
JavaMail 的关键对象
1> Properties : 属性对象,其中封装服务器地址、 端口、 用户名、 密码等信息,具体相关信息如下 :
属性名
属性类型
说明
mail.smtp.host
String
SMTP 服务器地址,如 smtp.sina.com.cnmail.smtp.port
int
SMTP 服务器端口号,默认为 25mail.smtp.auth
boolean
SMTP 服务器是否需要用户认证,默认为 falsemail.smtp.user
String
SMTP 默认的登录用户名mail.smtp.from
String
默认的邮件发送源地址mail.smtp.socketFactory.class
String
socket 工厂类类名,通过设置该属性可以覆盖提供者默认的实现。必须实现 javax.net.SocketFactory 接口mail.smtp.socketFactory.port
int
指定 socket 工厂类所用的端口号,如果没有设定,则使用默认的端口mail.smtp.socketFactory.fallback
boolean
设置为 true 时,当使用指定的 socket 类创建 socket 失败后,将使用 java.net.Socket 创建 socket。默认为 truemail.smtp.timeout
int
I/O 连接超时时间,单位为毫秒,默认为永不超时Session : 会话对象,是一堆配置信息的集合
Transport 和 Store : 传输和存储
使用 JavaMail 发送邮件实例
1> 引入 JavaMail 相关包
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
2>
importjavax.activation.DataHandler;
importjavax.activation.DataSource;
importjavax.activation.FileDataSource;
importjavax.mail.*;
importjavax.mail.internet.InternetAddress;
importjavax.mail.internet.MimeBodyPart;
importjavax.mail.internet.MimeMessage;
importjavax.mail.internet.MimeMultipart;
importjava.util.Properties;
public classMailUtils {
private String host = ""; // smtp服务器
private String from= ""; // 发件人地址
private String to= ""; // 收件人地址
private String affix= ""; // 附件地址
private String affixName= ""; // 附件名称
private String user= ""; // 用户名
private String pwd= ""; // 密码
private String subject= ""; // 邮件标题
public voidsetAddress(String from, String to, String subject) {
this.from= from;
this.to= to;
this.subject= subject;
}
public void setAffix(String affix, String affixName) {
this.affix= affix;
this.affixName= affixName;
}
public void send(String host, String user, String pwd, String content) {
this.host= host;
this.user= user;
this.pwd= pwd;
Properties props =new Properties();
// 设置发送邮件的邮件服务器的属性(这里使用网易的smtp服务器)
props.put("mail.smtp.host", host);
// 需要经过授权,也就是有户名和密码的校验,这样才能通过验证(一定要有这一条)
props.put("mail.smtp.auth","true");
// 用刚刚设置好的props对象构建一个session
Session session = Session.getDefaultInstance(props);
// 有了这句便可以在发送邮件的过程中在console处显示过程信息,供调试使
// 用(你可以在控制台(console)上看到发送邮件的过程)
session.setDebug(true);
// 用session为参数定义消息对象
MimeMessage message = new MimeMessage(session);
try {
// 加载发件人地址
message.setFrom(newInternetAddress(from));
// 加载收件人地址
message.addRecipient(Message.RecipientType.TO,new InternetAddress(to));
// 加载标题
message.setSubject(subject);
// 向multipart对象中添加邮件的各个部分内容,包括文本内容和附件
Multipart multipart = new MimeMultipart();
// 设置邮件的文本内容
BodyPart contentPart = new MimeBodyPart();
contentPart.setText(content);
multipart.addBodyPart(contentPart);
// 添加附件
BodyPart messageBodyPart = new MimeBodyPart();
DataSource source =new FileDataSource(affix);
// 添加附件的内容
messageBodyPart.setDataHandler(newDataHandler(source));
// 添加附件的标题
// 这里很重要,通过下面的Base64编码的转换可以保证你的中文附件标题名在发送时不会变成乱码
sun.misc.BASE64Encoder enc = new sun.misc.BASE64Encoder();
messageBodyPart.setFileName("=?GBK?B?"+ enc.encode(affixName.getBytes()) +"?=");
multipart.addBodyPart(messageBodyPart);
// 将multipart对象放到message中
message.setContent(multipart);
// 保存邮件
message.saveChanges();
// 发送邮件
Transport transport = session.getTransport("smtp");
// 连接服务器的邮箱
transport.connect(host, user, pwd);
// 把邮件发送出去
transport.sendMessage(message, message.getAllRecipients());
transport.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
MailUtils cn =new MailUtils();
// 设置发件人地址、收件人地址和邮件标题
cn.setAddress("chenshun131@163.com","1539831174@qq.com","一个带附件的JavaMail邮件");
// 设置要发送附件的位置和标题
cn.setAffix("/Users/chenshun131/Desktop/附录A.pdf","123.pdf");
/**
* 设置smtp服务器以及邮箱的帐号和密码
* 用QQ 邮箱作为发生者不好使 (原因不明)
* 163 邮箱可以,但是必须开启 POP3/SMTP服务 和 IMAP/SMTP服务
* 因为程序属于第三方登录,所以登录密码必须使用163的授权码
*/
// 注意: [授权码和你平时登录的密码是不一样的]
cn.send("smtp.163.com","chenshun131@163.com","","邮件的具体内容在此");
}
}
直接使用 JavaMail 编写邮件收发程序并不是一件轻松的事情,这归咎于 JavaMail 零散而复杂的 API 以及各种强制需要处理的检查型异常。Spring 对使用 JavaMail 发送邮件进行了很大程度的简化,它为 80%的需求提供了简单的处理方法,剩下的需求则可以通过直接调用 JavaMailAPI 完成
Spring 在 org.springframework.mail 包里通过 MailMessage 和 MailSender 这两个高层抽象接口描述了,两个最重要的内容 : 邮件消息和邮件发送者
MailMessage : 抽象的邮件消息,该接口描述了邮件消息的通用模型,允许开发者通过多个简洁的属性设置方法填充邮件消息的各项内容
MailMessage 有两个实现类: SimpleMailMessage 和 MimeMailMessage,前者都是完全符合 Bean 风格的实现类,后者通过内置 JavaMail 的 MimeMessage 提供实现。在发送简单文本型邮件时, SimpleMailMessage 就可以满足要求,如果 发送复杂的邮件,则可以利用 MimeMailMessage 或直接使用MimeMessage
MailSender : 抽象的邮件发送者,邮件发送者负责将邮件发送到指定的地址上,该接口只用于发送简单的邮件。如果需要发送复杂的邮件,则需要使用 JavaMailSender 子接口
Spring 的邮件异常体系
Spring 在 org.springframework.mail.javamail 包下提供了对 JavaMail 邮件系统的支持。首先,通过 JavaMailSenderImpl 可以方便地创建 JavaMail 环境;其次,通过 MimeMessageHelper 构造出 MimeMessage 对象
向邮件中添加附件或内嵌文件时,文件对应的 MIME 类型是一个很重要的信息,因为 Outlook、Foxmail 等邮件客户端软件必须根据 MIME 类型决定如何处理邮件中的内嵌文件。文件扩展名和 MIME 类型的对应关联在 activation.jar/META-INF 目录下的
mimetypes.default 文件中定义 :
MIME 类型的规范名
文件扩展名
text/html
html htm HTML HTM
text/plain
txt text TXT TEXT
image/gif
gif GIF
image/ief
ief
image/jpeg
jpeg jpg jpe JPG
image/tiff
tiff tif
image/x-xwindowdump
xwd
application/postscript
ai eps ps
application/rtf
rtf
application/x-tex
tex
application/x-texinfo
texinfo texi
application/x-troff
t tr roff
audio/basic
au
audio/midi
midi mid
audio/x-aifc
aifc
audio/x-aiff
aif aiff
audio/x-mpeg
mpeg mpg
audio/x-wav
wav
video/mpeg
mpeg mpg mpe
video/quicktime
qt mov
video/x-msvideo
avi
注 : 在 http://www.w3school.com.cn/media/media_mimeref.asp 可以找到所有 MIME 类型的信息
发送邮件频繁发送可能会被邮箱服务器识别为垃圾邮件,如 163邮箱可能会出现 554 DT:SPM 发送的邮件内容包含了未被许可的信息,或被系统识别为垃圾邮件。请检查是否有用户发送病毒或者垃圾邮件;
通过 Spring 的 JavaMail 发送各种形式的邮件
例如如下代码
@Autowired
privateJavaMailSender sender;
public voidsendSimpleMail() { // 发送纯文本邮件
SimpleMailMessage msg = new SimpleMailMessage();
msg.setFrom("chenshun131@163.com");
msg.setTo("chenshun131@gmail.com");
msg.setReplyTo("1539831174@qq.com");
msg.setCc("1539831174@qq.com");
msg.setSubject("注册成功");
msg.setText("恭喜,您在宝宝淘论坛已经注册成功!您的用户ID为:1234567890");
sender.send(msg);
}
public voidsendHtmlMail() throws MessagingException {// 发送 HTML 类型的邮件
MimeMessage msg = sender.createMimeMessage();
MimeMessageHelper helper =new MimeMessageHelper(msg, false,"utf-8");// 推荐使用 utf-8 编码
helper.setFrom("chenshun131@163.com");
helper.setTo(newString[]{"chenshun131@gmail.com","1539831174@qq.com"});
helper.setSubject("注册成功");
String htmlText ="<html><head>"
+ "<meta http-equiv=\"content-type\"content=\"text/html; charset=utf-8\">"
+ "</head><body>" + "恭喜,您在宝宝淘论坛已经注册成功!您的用户ID为:"
+ "<font size='20' size='30'>1234567890</font></body></html>";
helper.setText(htmlText,true);
sender.send(msg);
}
/**
* 对于一个 Web 应用程序来说,一般情况下,我们不推荐使用内嵌文件的邮件,用
* 户大可将这些资源文件放在一台 Web 资源服务器上,然后简单地通过 URL 来引用这
* 些文件。这带来了明显的好处:邮件体积缩小很多,并且提高了邮件的收发效率,同
* 时邮件的展现效果并不会受到影响
*/
public voidsendInlineMail() throws MessagingException {// 发送带内嵌文件的邮件
MimeMessage msg = sender.createMimeMessage();
// 内嵌文件邮件是 multipart类型,第二个入参需要设置为 true
MimeMessageHelper helper = new MimeMessageHelper(msg,true,"utf-8");
helper.setFrom("chenshun131@163.com");
helper.setTo(newString[]{"chenshun131@gmail.com","1539831174@qq.com"});
helper.setSubject("宝宝淘论坛注册成功");
String htmlText ="<html><head>"
+ "<meta http-equiv=\"content-type\"content=\"text/html; charset=utf-8\">"
+ "</head><body>" + "欢迎访问宝宝淘论坛!</hr>(我想显示一些其他信息)"
+ "<div><img src=\"cid:img01\"></img></div>"+ "</body></html>";
helper.setText(htmlText,true);
ClassPathResource img =new ClassPathResource("bbt.gif");
helper.addInline("img01", img);
sender.send(msg);
}
public voidsendAttachmentMail() throws Exception {// 发送带附件的邮件
MimeMessage msg = sender.createMimeMessage();
MimeMessageHelper helper =new MimeMessageHelper(msg, true,"utf-8");
helper.setFrom("chenshun131@163.com");
helper.setTo(newString[]{"chenshun131@gmail.com","1539831174@qq.com"});
helper.setSubject("宝宝淘论坛注册成功");
helper.setText("欢迎访问宝宝淘论坛!");
ClassPathResource file1 =new ClassPathResource("bbt.zip");
helper.addAttachment("file01.zip", file1.getFile());
ClassPathResource file2 =new ClassPathResource("file.doc");
helper.addAttachment("file02.doc", file2.getFile());
sender.send(msg);
}
// 双版本邮件,在 Foxmail 中,用户在默认情况下看到纯文件版本的邮件,可以通过点击工具栏的“ HTML”按钮查看 HTML 版本的邮件
public voidsendAlternativeMail() throws Exception {// 发送纯文本和 HTML 双版本的邮件
MimeMessagePreparator mmp = new MimeMessagePreparator() {
public void prepare(MimeMessage msg)throws Exception {
MimeMessageHelper helper =new MimeMessageHelper(msg, true,"utf-8");
helper.setFrom("chenshun131@163.com");
helper.setTo(newString[]{"chenshun131@gmail.com","1539831174@qq.com"});
helper.setSubject("注册成功");
MimeMultipart mmPart =new MimeMultipart("alternative");// 创建双版本邮件内容
msg.setContent(mmPart);
// 创建纯文本版本的邮件体
BodyPart plainTextPart = new MimeBodyPart();
plainTextPart.setText("欢迎访问宝宝淘论坛!(创建纯文本版本的邮件体)");
mmPart.addBodyPart(plainTextPart);
// 创建 HTML 版本的邮件体
BodyPart htmlPart = new MimeBodyPart();
String htmlText ="<html><head>"
+ "<meta http-equiv=\"content-type\"content=\"text/html; charset=utf-8\">"
+ "</head><body><font size='20' size='30'>"
+ "欢迎访问宝宝淘论坛! (创建 HTML 版本的邮件体)</font>" + "</body></html>";
htmlPart.setContent(htmlText,"text/html;charset=utf-8");
mmPart.addBodyPart(htmlPart);
}
};
sender.send(mmp);
}
需要在 Spring 工程中引入两个库
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
在 spring-mvc.xml 中配置发送者邮件相关信息
<beanid="sender"
class="org.springframework.mail.javamail.JavaMailSenderImpl"
p:host="smtp.163.com"
p:username="chenshun131"
p:password="xxxx">
<propertyname="javaMailProperties">
<props>
<propkey="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
在实际应用中发送邮件
邮件发送程序直接在代码中构建邮件内容,对于一些简单的邮件来说,这种方式是可行的。但如果邮件体的内容很复杂,这种方式的弊端将马上暴露出来 —— 直接使用 Servlet 构造复杂内容网页非常复杂
对于 HTML 格式的邮件来说,除少部分内容外,大部分的 HTML 代码都是固定的,因此,在实际应用中,常采用的办法是制作好邮件模板,在发送邮件时,通过模板解析构建最终邮件内容
由于发送邮件相对来说是比较重量级的操作,它受限于邮件服务器和网络的性能,可能需要好几秒的时间。如果直接在业务流程的线程中采用同步的方式发送邮件,业务流程的响应速度将会受到很大的影响。为了降低这种影响,在实际的应用系统中,一般需要采用异步邮件发送方式,使用单独的线程发送邮件,甚至使用 JMS 消息提交邮件发送任务,由单独的邮件发送服务器负责实际邮件发送的任务
使用邮件模板
在开源领域, Velocity 和 FreeMarker 是广泛使用的两个模板框架,由于 FreeMarker 的后发优势其更受青睐度。模版的原理其实很简单,就是用动态的数据替换模板中的特殊标签,生成最终的内容
Spring 为 Freemarker 提供了一个 FreeMarkerConfigurer,通过这个类可以方便地创建Freemarker 的基础设施,然后就可以在此基础上获取 Freemarker 的基础组件实例
例如如下代码 :
@Autowired
private JavaMailSender sender;
@Autowired
privateFreeMarkerConfigurer freeMarkerConfigurer;
@Test
public voidsendTemplateMail() throws MessagingException {
MimeMessage msg =sender.createMimeMessage();
MimeMessageHelper helper =new MimeMessageHelper(msg, false,"utf-8");
helper.setFrom("chenshun131@163.com");
helper.setTo(newString[]{"chenshun131@gmail.com","1539831174@qq.com"});
helper.setSubject("宝宝淘论坛注册成功:基于模板");
String htmlText = getMailText("1234567890");// 使用模板产生HTML 邮件体内容
helper.setText(htmlText, true);
sender.send(msg);
}
privateString getMailText(String userId) {// 通过模板构造邮件内容
String htmlText = null;
try {
Template tpl =freeMarkerConfigurer.getConfiguration().getTemplate("registerUser.ftl");// 通过指定模板名获取 Freemarker 模板实例
Map map = new HashMap();// 通过 Map 传递动态数据
map.put("userId", userId);// 注意动态数据的名字必须和模板标签中指定属性相匹配
htmlText = FreeMarkerTemplateUtils.processTemplateIntoString(tpl, map);// 解析模板并替换动态数据,产生最终的内容
} catch (Exception e) {
throw new RuntimeException(e);
}
return htmlText;
}
在 spring-mvc.xml 中配置 freemarker发送者邮件相关信息
<beanid="freeMarkerConfigurer"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
p:templateLoaderPath="classpath:mailTemplate/">
<propertyname="freemarkerSettings">
<props>
<propkey="template_update_delay">1800</prop>
<propkey="default_encoding">UTF-8</prop>
<propkey="locale">zh_CN</prop>
</props>
</property>
</bean>
registerUser.ftl 中的信息
<html>
<head>
<metahttp-equiv="content-type"content="text/html; charset=utf-8">
</head>
<body>
恭喜,您在宝宝淘论坛已经注册成功!您的用户ID为:<fontsize='20'size='30'>${userId}</font>
</body>
</html>
异步发送邮件
例如如下代码 :
@Autowired
private TaskExecutor taskExecutor;// 拥有异步执行能力的任务执行器
@Test
public voidsendAsyncMail() {
taskExecutor.execute(newRunnable() {
public void run() {
try {
sendTemplateMail();// 异步调用 sendTemplateMail()方法发送邮件
System.out.println("邮件发送成功!");
} catch (Exception e) {
System.out.println("邮件发送失败!,异常信息:"+ e.getMessage());
}
}
});
}
在 spring-mvc.xml 中配置任务执行器信息
<beanid="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
p:corePoolSize="10"
p:maxPoolSize="30"/>
阅读全文
0 0
- java 发送邮件 详解
- Java邮件发送详解
- 代码详解java发送邮件
- 详解java mail 发送邮件
- Java邮件发送详解(可发送附件)
- 邮件发送详解
- Android邮件发送详解
- Android邮件发送详解
- 邮件发送详解
- Android邮件发送详解 .
- Android邮件发送详解
- python发送邮件详解
- [java]Java发送邮件
- java 邮件发送 --- 简单的邮件发送
- JAVA发送邮件及springboot发送邮件
- 怎么用java发送带附件的邮件代码详解
- 用java发送邮件
- 用Java发送邮件
- Glide读取图片
- python列表基础操作
- 欢迎使用CSDN-markdown编辑器
- js中获取元素属性、currentStyle与getComputedStyle的区别
- 多按钮居中显示
- java 发送邮件 详解
- mac下的strace命令
- linux 上使用commons-net.jar中 FTPClient类的listFiles、retrieveFile等方法停止不执行,出现假死状态解决办法
- C# winform和webform通用的加密解密方法UrlEncode和UrlDecode
- linux git客户端命令
- MySQL慢查询日志总结
- Komodo Edit 10中文注释问题
- 华为机考2015(2)JAVA实现
- CentOS 配置多网卡及简单路由设置