邮件开发
前一篇文章我们完成了众筹项目中manager程序当中的整个权限管理的开发,项目中普通的增删改查,RBAC权限模型、以及页面中树形结构的显示,模态框的显示,我们都已经了解啦!接下来呢!我们应该尝试新的功能啦,也是很多程序都拥有的基本功能,(忘记密码与自动登录功能),相信这两个功能对我们来说并不陌生,但是他们是如何实现的呢?对于忘记密码,我们应该都使用过这个功能,目前忘记密码有两种找回密码的方式:一种是手机短信的方式找回密码,另一种就是发送邮件的方式找回密码;我们这里就选择使用发送邮件的方式找回密码吧!原因也很简单,免费!!!那在实现忘记密码这个功能之前呢!我们就先来了解一下邮件开发的相关知识吧!
Java官方支持邮件开发;javax-mail;这个包默认在jdk里面没有,需要去oracle的主页下载;可以使用maven坐标;
文档-javamail发送邮件
虽然官方提供了邮件开发的api javax-mail,但是他对我们来说还不够简单。通常我们使用Commons-email这个开源工具,他是基于javax-mail开发的,可以让我们使用起来更加方便。
接下来是几个Commons-email的几个例子。
一个简单的纯文本邮件
咱第一个例子是创建一个简单的email,并通过Google Mail(GMail)账号把发给"John Doe"。
Email email = new SimpleEmail();
email.setHostName("smtp.googlemail.com");
email.setSmtpPort(465);
email.setAuthenticator(new DefaultAuthenticator("username", "password"));
email.setSSLOnConnect(true);
email.setFrom("user@gmail.com");
email.setSubject("TestMail");
email.setMsg("This is a test mail ... :-)");
email.addTo("foo@bar.com");
email.send();
setHostName("mail.myserver.com")是设置SMTP服务器。如果不设置,默认是"mail.host".
发送带附件的邮件
得用MultiPartEmail 类来给邮件添加附件。除过覆盖attach()方法来给邮件添加附件外,这个类就和SimpleEmail类差不多。对于内联或是加入附件的个数是没有限制的。但附件必须是MIME编码。
最简单的添加附件的方式是用 EmailAttachment类。
下面的例子是将图片作为邮件的附件,并发送出去。
import org.apache.commons.mail.*;
...
// Create the attachment
EmailAttachment attachment = new EmailAttachment();
attachment.setPath("mypictures/john.jpg");
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription("Picture of John");
attachment.setName("John");
// Create the email message
MultiPartEmail email = new MultiPartEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("The picture");
email.setMsg("Here is the picture you wanted");
// add the attachment
email.attach(attachment);
// send the email
email.send();
如果你没有本地文件,你可以用 EmailAttachment 添加任何可用的URL。当邮件发送后,文件会自动加载并加入到邮件内容。
下面的例子是将Apache logo图片发给John。
import org.apache.commons.mail.*;
...
// Create the attachment
EmailAttachment attachment = new EmailAttachment();
attachment.setURL(new URL("http://www.apache.org/images/asf_logo_wide.gif"));
attachment.setDisposition(EmailAttachment.ATTACHMENT);
attachment.setDescription("Apache logo");
attachment.setName("Apache logo");
// Create the email message
MultiPartEmail email = new MultiPartEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("The logo");
email.setMsg("Here is Apache's logo");
// add the attachment
email.attach(attachment);
// send the email
email.send();
发送带HTML格式的邮件
发送HTML格式的邮件可用很成熟的HtmlEmail类。这个类和MultiPartEmail差不多,就是增加了设置HTML内容的方法,对于不兼容THML文本和内联图片的邮件,它会将HTML转化为文本。
下面的例子就是发送带内联图片HTML格式的邮件。
import org.apache.commons.mail.HtmlEmail;
...
// Create the email message
HtmlEmail email = new HtmlEmail();
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("Test email with inline image");
// embed the image and get the content id
URL url = new URL("http://www.apache.org/images/asf_logo_wide.gif");
String cid = email.embed(url, "Apache logo");
// set the html message
email.setHtmlMsg("<html>The apache logo - <img src=\"cid:"+cid+"\"></html>");
// set the alternative message
email.setTextMsg("Your email client does not support HTML messages");
// send the email
email.send();
请注意, embed方法返回的是字串。这个字串是随机生成的标识,将来用到图片标签里。
接下来没有调用HtmlEmail类的setMsg方法,因为如果HTML内容里有内联图片的话,这个方法是不能用的。这样我们可以用setHtmlMsg和setTextMsg方法。
发送带嵌入图片的HTML文本
前面讲过如何创建带嵌入图片的HTML邮件,但是你得知道用HTML邮件模板来处理图片是很麻烦的。ImageHtmlEmail类能解决这个问题,它能很方便的让你将所有外部图片转化为内联图片。
import org.apache.commons.mail.HtmlEmail;
...
// load your HTML email template
String htmlEmailTemplate = ....
// define you base URL to resolve relative resource locations
URL url = new URL("http://www.apache.org");
// create the email message
HtmlEmail email = new ImageHtmlEmail();
email.setDataSourceResolver(new DataSourceResolverImpl(url));
email.setHostName("mail.myserver.com");
email.addTo("jdoe@somewhere.org", "John Doe");
email.setFrom("me@apache.org", "Me");
email.setSubject("Test email with inline image");
// set the html message
email.setHtmlMsg(htmlEmailTemplate);
// set the alternative message
email.setTextMsg("Your email client does not support HTML messages");
// send the email
email.send();
首先我们创建了带图片的HTML邮件模板。所有涉及的图片都会在当前目录里自动转化为内联图片。
调试
JavaMail API支持调试选项,通过调用setDebug(true)来开启调试。调试信息会通过System.out打印出来。
有时你会关心commons-email的安全设置的特性。可以用EmailLiveTest和EmailConfiguration类在真正的SMTP服务器上测试commons-email.
认证
如果你要对SMTP服务器进行认证,可以在发邮件前调用setAuthentication(userName,password)方法测试。这将会在JavaMail API发送邮件时创建DefaultAuthenticator实例,要支持此方法得让你的服务器支持RFC255协议。
你可以用javax.mail.Authenticator的子类来完成更加复杂的认证,如弹出个对话框等。当你想收集并处理用户信息时,你必须覆盖getPasswordAuthentication()方法。用Email.setAuthenticator方法可以创建新的Authenticator类。
安全
如今,在使用公共邮件服务器的时候你不应该使用普通的SMTP代理,但是可选项对大家来说还是有些不熟悉。
通常有以下两个可选项:
- 通过25端口的STARTTLS方式
- 通过465端口的SSL方式
下面是wiki百科上的定义:
- STARTTLS是一个纯文本的通信协议,它提供了一个纯文本连接的方式来升级到一个加密(TLS或SSL)连接,而不是使用单独的端口进行加密通信的扩展。
- 传输层安全性(TLS)和安全套接字层(SSL),其前身是加密协议,提供通信安全的Internet.TLS和SSL加密,在传输层之上的网络连接段,使用非对称加密的密钥交换,对称加密隐私,消息完整性和消息认证码。
此外,你还可以强制进行以下的安全检查(默认情况下是禁用的)
- 当使用安全的传输(STARTTLS或SSL)时,你可以通过设置Email.setSSLCheckServerIdentity(true)强制验证服务器的证书。但这在任何我测试过的服务器上好像都没有作用(GMAIL,GMX)。
- 通过设置Email.setStartTLSRequired(true)强制使用STARTTLS。
退回邮件处理
通常情况下,不能投递给收件者的邮件将会退回给发件人(从属性指定)。然而,在某些情况下,你会希望这些被发送到不同的地址。要做到这一点,只需调用setBounceAddress(emailAddressString)方法设置电子邮件地址,然后发送电子邮件。
技术说明:当SMTP服务器不能投递邮件时,它们根本不关心那些决定错误应该发送去哪的消息的内容。相反,他们使用是SMTP“信件发件人”中的值。JavaMail通过JavaMailSession的mail.smtp.from属性来设置这个值(普通邮件是使用System.getProperties()来初始化JavaMailSession 的)。如果这个值没有被设置,JavaMail将会使用“发件人”地址。如果你的邮件设置回退邮件地址属性集合,普通邮件将会使用这个值来覆盖Session初始化时的mail.smtp.from属性的值。
注意:这是控制处理退回邮件的唯一方式。具体来说,“Errors-to”这个SMTP头已经被废弃,不能被用来进行退回邮件处理。另外请注意,用一个不受信任的邮件地址发邮件也被认为是不好的做法,除非你还可以设置退回地址。如果你的应用允许用户输入一个地址用作发件人”地址,回退地址一定要设置一个已知好的邮件地址。
不过,这里推荐使用推荐使用commons-email;它使用起来更简单方便。
Commons-email使用
•commons-email是apache-commons项目下的一个小模块工具,可以简化我们的邮件开发
•http://commons.apache.org/proper/commons-email/index.html
•几个重要的类:
–SimpleEmail:简单的邮件
–EmailAttachment:邮件附件
•需要使用multipartEmail.attach(attachment)
•attachment.setPath()/setUrl()添加附件
–HtmlEmail,ImgHtmlEmail
•具有html片段&嵌入img标签的email
使用起来也很简单,在maven中添加依赖就可以啦!
使用163邮箱进行测试。
这里使用163的邮箱向我们公司的邮箱发送邮件可是成功,我们公司的邮箱也可以接受到。但是向qq邮箱发送邮件就收不到,邮件被放到了垃圾箱中!qq的垃圾邮件机制比较头疼。
这里还有个地方需要注意。在代码中登录163邮箱是需要授权第三方登录的。不然登录不了。
授权方法如下
然后代码中输入邮箱账号和密码时的密码就不再是邮箱的密码啦!而是你刚刚设置授权第三方登录的授权码。
Apache-James邮件服务器快速使用
•James是一个开源的模块化的邮件服务器,并配套整体解决方案,包括各种协议的实现,hupa客户端,Mail Protocol Tester (MPT),Mailet等
•下载Apache-James
–http://james.apache.org/server/index.html
•解压放在非中文无空格目录下
Apache-James快速使用
•1、根据官方文档提示,解压运行即可,不过我这里报错,运行不起来,一闪而过。解决办法请看 步骤2;
•2、jdk7会产生jaxb包冲突,在conf/lib下引入jaxb包接口,再去运行就没问题啦。
•3、修改conf下配置文件,需要覆盖默认配置的去掉-template即可(带-template的配置文件是模板文件光修改内容是不会被使用的,修改完内容后还需要将文件名字中的-template去掉,这样才会被使用,比如步骤4),修改这个配置文件件是改变数据库为mysql数据库
•4、修改database.properties文件使用MySQL存储邮件信息
为Apache-James创建一个使用的数据库email。
•5、conf/lib导入mysql驱动包
•6、然后重新启动James。
•7、查看数据库信息。James邮件服务器自己的数据库表已经创建在了mysql中,我们的配置生效啦
•8、可是现在的邮件服务器还是一个空白的,既没有域名信息,也没有用户。所以我们需要绑定域名,并添加用户信息。我们就用命令行的方式添加域名和用户信息把。
为本机地址9999端口绑定域名test123.com
分别创建了用户名为admin@test123.com 密码为123456和test1@test123.com秘密为123456的两个用户。
看看数据库中创建成功了没有。
其实我知道了域名和用户信息存在哪张表中的话,不使用命令行直接向表中添加数据也可以。
•9、使用foxmail创建账号测试
注意这里的接收和发送邮件服务器填的是127.0.0.1,因为我们并没有服务器。所以James默认使用本机作为服务器。
使用test1账号为admin账号发送一封测试邮件。
使用代码的方式也是可以的。
不过在向外网发邮件的时候有点问题。向163的邮箱发邮件可以正常接收。但是向qq的邮箱发送邮件时,可以发送成功,但是qq邮箱却没有邮件,打开垃圾箱,发现发送过来的邮件在垃圾箱中。我想应该是qq的垃圾邮件机制的问题吧。
现在虽然可以向外网发送邮件,但是外网向我们自己创建的邮箱发邮件却不行,因为我们自己的邮箱服务是在局域网内而不是在公共网络中,别的邮件服务器找不到我们。
最后附上我自己保存的James服务器的地址:https://download.csdn.net/download/qq_25106373/11217445
其中不止有James程序包,还有用于解决jdk7以上版本jar包冲突的jaxb-impl-2.1.3.jar,已经用于测试的Foxmail客户端(免安装的)。