day19 javamail

什么情况需要邮件发送?
1、注册后,账户激活功能 (获得有效真实邮箱地址)
2、商城广告邮件
3、节日祝福
4、系统对用户功能通知,可以通过邮件

今天学习目标:通过java程序发送邮件

邮件服务器? 网络中一台电脑,在电脑安装邮件服务器端软件,需要对服务器进行配置

电子邮箱? 邮件服务器上账户,可以通过电子邮箱登陆 邮件服务器
* 服务器会为每个邮箱账户,分配一定空间,用来保存邮箱相关电子邮件

邮件收发协议? SMTP、POP3、IMAP
SMTP 发送邮件协议,默认端口25
POP3 收取邮件协议,默认端口110
* 协议是用来规定通信格式的
IMAP 收取邮件协议,默认端口143,允许用户在线操作邮件,而不需要将邮件下载 ------- GMAIL开发IMAP权限

收发邮件过程是怎么样?
1、[email protected] 通过新浪客户端 连接新浪smtp服务器,发送邮件
2、新浪是smtp 需要将信件转投 给搜狐的 smtp服务器
3、搜狐smtp 获得邮件后,会将邮件保存 [email protected] 对应邮箱空间里
4、[email protected] 通过搜狐客户端,连接搜狐pop3服务器,pop3会读取bbb对应邮箱空间,获得aaa发送的邮件,返回客户端显示邮件内容

手动收发邮件实验
1、在sina和sohu 分别注册两个邮箱账户
sina:  [email protected] / 1qaz2wsx
sohu: [email protected] /1qaz2wsx
2、用sina向sohu发送一封邮件,通过telnet(socket程序) 手动根据协议发送邮件
3、安装telnet

抄送:A 发给B ,选择抄送给C , B可以看见邮件抄送给 C (邮件是给B的,需要让C知道B已经收到邮件)
暗送:A 发给B,选择暗送给C ,B可以看见邮件,但是不能看到邮件发给C (邮件给B,也想给C一份,但不想让B知道)

4、使用SMTP发送邮件  连接新浪smtp : telnet stmp.sina.com 25

ehlo xxx   ----- SMTP2代 helo
auth login   ----- 发邮件时,发给服务器用户名和密码必须使用base64编码

eXV5YW5nOTQ4OTU=
MXFhejJ3c3g=

mail from:<[email protected]>  ----- 发件人
rcpt to:<[email protected]>    ----- 收件人

data   ------ 邮件内容

from:<[email protected]>
to:<[email protected]>
subject:第一封0713测试邮件

这是一封测试邮件,哈哈~~~~
.  

quit  ----- 退出客户端

5、安装易邮
工具 --- 服务器设置 ---- 修改单域名 estore.com     -------------------- [email protected]
账户 --- 新建账户  aaa/111 bbb/111
[email protected][email protected] 发送一封邮件

6、smtp连接易邮发件
连接易邮smtp服务器 telnet localhost 25

ehlo xxx   ----- SMTP2代 helo
auth login   ----- 发邮件时,发给服务器用户名和密码必须使用base64编码

YWFh
MTEx

mail from:<[email protected]>  ----- 发件人
rcpt to:<[email protected]>    ----- 收件人

data   ------ 邮件内容

from:<[email protected]>
to:<[email protected]>
subject:第一封0713测试邮件

这是一封测试邮件,哈哈~~~~
.  

quit  ----- 退出客户端

7、pop3连接易邮收取邮件
连接易邮pop3服务器 telnet localhost 110
user bbb
pass 111

stat ----- 返回邮箱的统计信息
list 邮件号 ------  邮件信息
retr 邮件号 ------ 收取邮件内容

quit

-----------------------------------------------------------------------------------------------------------------------------------------------
telnet win7 输入中文 ? 问题 ---- 客户端本身问题
putty 小工具 模拟客户端,采用多种连接协议 连接服务器 ------  企业使用远程连接操作linux
对putty设置
window --- Translation (Use font encoding 就是系统默认编码集gbk)   ------------------- 可以将字符集设为utf-8 , window不需要
window --- appearance ---- change 字体显示中文字体(新宋体) 字符集 gb2312
Session中对ip port 和协议进行配置

两种客户端收发邮件软件使用:foxmail、outlook
* 定时收发邮件,提醒用户有新的邮件
1、foxmail 安装配置
邮箱 --- 新建邮箱账户
输入邮箱 密码点击下一步
* 在foxmail安装目录/mail目录/ 每配置一个邮箱 出现一个文件夹
配置pop3 ---- 需要写真实服务器地址 ---- 易邮localhost
配置smtp

2、outlook 安装配置
工具 --- 电子邮箱账户 ---- 添加新电子邮件账户
其它设置 --- 发送服务器 --- 勾选我的发送服务器要求验证    
其它设置 --- 高级 ---- 勾选在服务器上保留邮件副本
* win7 无法连通本地易邮
cmd> ping localhost ---- ::1 ---- 解决在hosts文件 添加127.0.0.1 localhost

RFC822文档 规定邮件内容格式 区分和smtp ?
SMTP 通信协议,规定发送邮件时,客户端与服务器通信数据格式
RFC822文档 对邮件中文规定

邮件内容 包括邮件头和邮件体
邮件头 from(发件人) to(收件人) subject(标题) cc(抄送) bcc(暗送)
邮件体 : 邮件正文内容,需要和邮件头以一个空行分隔

RFC822文档 规定一封简单邮件如何编写,本身存在漏洞
* 发邮件过程中 mail from字段 和 RFC822文档 from字段 不同会出现什么问题? 冒名邮件问题
* 对方收取邮件时,只能看到from字段内容,无法得知mail from 地址
ehlo xxx
auth login
YWFh
MTEx
mail from:<[email protected]>
rcpt to:<[email protected]>

data
from: <[email protected]>
to:<[email protected]>
subject:面试通知

尊敬的李先生,我们已经看过您的简历,发觉您的简历,非常符合我公司搜索研发部,Android开发技术经理职位,请于2012年4月1日到中关村科贸大厦12层B座1205室参加面试。

google人力资源部
2012.1.1
.
--------------------------------------------------------------------------------------------------------------------------
JavaMail 是一套sun 提供开发邮件收发程序API,JavaMail编写程序就是邮件客户端程序(和outlook、foxmail功能类似)
* JavaMail开发需要类库 javamail API ,还需要下载 Java Activation Framework (jaf)  ---- javamail API 依赖 jaf

导入jar包
mail.jar activation.jar(JDK6.0以后官方API自带)
* JDK6.0 以后开发 只需要导入 mail.jar  ----- rt.jar 提供javax.activation 开发包
* JDK5.0(包括) 之前开发,需要导入mail.jar 和 activation.jar

javax.mail.Message 类 ----- 代表邮件本身
* 在javamailAPI中 一个邮件 就是一个Message对象
* 开发中使用javax.mail.internet.MimeMessage 代表邮件

javax.mail.Session 类 ----- 代表与服务器连接会话(简单理解连接)

***** java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream 异常
MyEclipse 中javaee.jar 提供javamai API 与 JavaMail 引入jar包发生冲突
解决 :删除javaee.jar里面的mail目录和activation目录

window --- preferences --- 搜索lib ----- Library sets

JAVAMAIL 邮件收发四个核心类
1、Message 邮件
2、Session 连接会话
3、Transport 发送邮件
4、Store 收取邮件

发送邮件编程
1、创建与邮件发送服务器连接Session
2、编写邮件内容 Message
* 符合邮件内容格式RFC822文档 setFrom setRecipients setSubject setText
3、使用Transport工具类 发送邮件
    @Test
    public void demo2() throws MessagingException {
        Properties properties = new Properties();
        // 设置properties 属性
        properties.put("mail.transport.protocol", "smtp");
        properties.put("mail.smtp.host", "smtp.exmail.qq.com");
        properties.put("mail.smtp.auth", "true");// 连接认证
        properties.put("mail.debug", "true");// 在控制台显示连接日志信息
        Session session = Session.getInstance(properties);
        // 步骤二 编写Message
        MimeMessage message = new MimeMessage(session);// 代表一封邮件
        // from字段
        message.setFrom(new InternetAddress("[email protected]"));
        // to 字段
        message.setRecipients(Message.RecipientType.TO, "[email protected]");
        // subject字段
        message.setSubject("javamail发送简单邮件");
        // 邮件正文内容
        message.setText("使用javamail 可以发送简单邮件 ...");

        // 步骤三 使用Transport发送邮件
        Transport transport = session.getTransport();
        // 发邮件前进行身份校验
        transport.connect("[email protected]", "123");
        transport.sendMessage(message, message.getAllRecipients());
    }
-------------------------------------------------------------------------------------------
RFC822 只定义简单邮件格式,没有定义复杂邮件如何编写
MIME 协议 是 RFC822文档的升级补充,完全支持RFC822文档

MIME 将邮件体分成多个部分,每个部分使用分隔线进行分隔,为每个部分提供Content-Type 类型属性

MIME描述邮件多个部分之间关系
1、multipart/mixed 用于携带附件
2、multipart/related 内嵌图片,音乐
3、multipart/alternative 防止兼容问题
* 发送简历时,将简历文件与邮件正文关系设置为alternative,当邮件客户端如果支持简历格式,简历会显示在正文中,如果不支持简历格式,简历会以附件携带

如果发送复杂邮件时,需要携带附件,需要为附件部分,设置Content-Disposition属性,值attachment
* 语法 Content-Dispostion : attachment;filenam=文件名

内嵌图片或者其他资源是,内嵌资源需要提供Content-ID属性,作为该资源唯一标识
* 在邮件正文中通过 <img src="cid:唯一标识" /> 引用内嵌图片和资源

JavaMail怎样描述一封复杂邮件
MimeMessage ----- 整封邮件
MimeBodyPart ---- 邮件每个部分
MimeMultiPart ---- 将BodyPart进行整合
1、判断邮件由几个部分组成,每个部分设计BodyPart
2、将BodyPart组合起来 ---- MultiPart(只有BodyPart之间可以组合,MultiPart不可以和其它BodyPart直接组合,需要组合将MultiPart转换BodyPart)
3、将最后合成MultiPart 交给MimeMessage 对象

总结一下:
1、发送内嵌图片 :图片设置ContentID,在邮件正文中cid:设置id引用目标图片,实现内嵌效果  ---- 图片关系related
2、发送携带附件 :附件中文名,setFileName设置,通过MimeUtility 对中文附件名进行编码 ---- 自动生成Content-Disposition字段 ---- 附件关系mixed
@Test
    // 内嵌图片邮件
    public void demo3() throws Exception {
        // 发送邮件需要三个步骤
        // 步骤一:创建Session
        Properties properties = new Properties();
        properties.put("mail.transport.protocol", "smtp");
        properties.put("mail.smtp.host", "localhost");
        properties.put("mail.smtp.auth", "true");// 连接认证
        properties.put("mail.debug", "true");// 在控制台显示连接日志信息
        Session session = Session.getInstance(properties);// 与邮件服务器连接会话
        // 步骤二:创建Message
        MimeMessage message = new MimeMessage(session);
        // 设置邮件头(简单邮件和复杂邮件相同
        message.setFrom(new InternetAddress("[email protected]"));
        message.setRecipients(Message.RecipientType.TO, "[email protected]");
        message.setSubject("javamail发送内嵌图片邮件");
        // 设置邮件体(简单邮件和复杂邮件区别 就在于邮件体)
        MimeBodyPart pic = new MimeBodyPart();// 图片
        // 链接数据文件
        pic.setDataHandler(new DataHandler(new FileDataSource("beauty.jpg")));
        // DataSource dataSource = new FileDataSource("beauty.jpg");
        // DataHandler dataHandler = new DataHandler(dataSource);
        // pic.setDataHandler(dataHandler);

        // 设置一个唯一标识(用于在正文中引入)
        pic.setContentID("mypic");

        MimeBodyPart content = new MimeBodyPart(); // 邮件正文
        content.setContent("<h1>美女图片</h1><img src='cid:mypic' />",
                "text/html;charset=utf-8");

        // 将两个BodyPart整合
        MimeMultipart mimeMultipart = new MimeMultipart();
        mimeMultipart.addBodyPart(pic);
        mimeMultipart.addBodyPart(content);

        // 设置关系
        mimeMultipart.setSubType("related");

        message.setContent(mimeMultipart);
        // message.writeTo(System.out);

        // 步骤三:Transport发送邮件
        Transport transport = session.getTransport();
        transport.connect("aaa", "111");
        transport.sendMessage(message, message.getAllRecipients());
    }
@Test
//发送附件
    public void demo3() throws MessagingException, UnsupportedEncodingException {
        Properties properties = new Properties();
        // 设置properties 属性
        properties.put("mail.transport.protocol", "smtp");
        properties.put("mail.smtp.host", "smtp.exmail.qq.com");
        properties.put("mail.smtp.auth", "true");// 连接认证
        // properties.put("mail.debug", "true");// 在控制台显示连接日志信息
        Session session = Session.getInstance(properties);
        // 步骤二 编写Message
        MimeMessage message = new MimeMessage(session);// 代表一封邮件
        // from字段
        message.setFrom(new InternetAddress("[email protected]"));
        // to 字段
        message.setRecipients(Message.RecipientType.TO, "[email protected]");
        // subject字段
        message.setSubject("javamail发送携带附件邮件");
        // 邮件正文内容
        MimeBodyPart attache = new MimeBodyPart();
        attache.setDataHandler(new DataHandler(new FileDataSource(
                "大嘴巴 - maybe的机率.mp3")));
        // 中文附件名的编码
        attache.setFileName(MimeUtility.encodeText("大嘴巴 - maybe的机率.mp3"));// 自动生成mime
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("<h1>附件是歌曲</h1>", "text/html;charset=utf-8");
        MimeMultipart mm = new MimeMultipart();
        mm.addBodyPart(attache);
        mm.addBodyPart(text);
        mm.setSubType("mixed");
        message.setContent(mm);
        // 步骤三 使用Transport发送邮件
        Transport transport = session.getTransport();
        // 发邮件前进行身份校验
        transport.connect("[email protected]", "xxx");
        transport.sendMessage(message, message.getAllRecipients());
    }
   
--------------------------------------------------------------------------------------------------------------------
邮件发送综合案例:注册账户,发送激活邮件,去邮箱激活,进行登陆
* 如果账户未激活情况下,不允许用户登陆
1、功能一:用户注册(用户名、密码、邮箱)--- 在注册服务器端,发送一封激活邮件
2、功能二:去邮件,进行邮件激活
3、功能三:用户登陆(判断用户账户是否激活)

create table user(
   id int primary key auto_increment,
   username varchar(40) unique,
   password varchar(40),
   email varchar(100) unique ,
   state int ,
   activecode varchar(100),
   updatetime timestamp
);

state为1 账户已经激活 state为0 账户未激活
activecode 激活码,在服务器端生成,当用户注册后,将激活码发到对方邮箱,并且将激活码保存数据库
账户激活有时间要求,在数据表保存updatetime,控制用户按时进行激活

***** 编写定时器 每隔6小时 运行一次,判断哪个账户已经24小时未激活,未激活,删除用户(发送通知邮件)


Tomcat对JavaMail的支持(JNDI访问) ----- 之前学习tomcat数据库连接池
1、在tomcat启动时,准备javamail 的session对象
2、在Servlet、JSP 通过JNDI方式 访问容器中Session对象
3、获得Session对象,发送邮件

配置javamail/Session
<Context>
  <Resource name="mail/Session" auth="Container"
            type="javax.mail.Session"
            mail.smtp.host="localhost"
            mail.transport.protocol="smtp"
            mail.smtp.auth="true"
  />
</Context>

***** java.lang.ClassCastException: javax.mail.Session cannot be cast to javax.mail.Session
错误位置:Session session = (Session) envCtx.lookup("mail/Session");
错误原因:Java中类加载器顺序 (tomcat创建Session使用common加载器,加载tomcat/lib , Servlet中Session使用当前应用类加载器,加载WEB-INF/lib)

.java ---- 编译 ---- .class ----- 需要被JVM的类加载器程序进行加载 ---- java.lang.Class类对象
解决:将当前工程WEB-INF/lib/mail.jar删除

----------------------------------------------------------------------------------------------
MX与A记录(配置邮件服务器相关的信息)
MX记录:在DNS中进行注册,目的让其它服务器找到服务器地址
* 通过nslookup
set type=mx
sina.com

freemx.sinamail.sina.com.cn  DNS查询MX记录 (发信不需要登陆)
smtp.sina.com 从网站上获得地址 (发信需要先登陆)

***** 如果连接MX记录中新浪服务器地址,发信,是不是也不需要登陆? A记录校验
*如果你用搜狐身份连接 新浪mx记录服务器,新浪服务器中会通过A记录 校验你的身份?

set type=a
sohu.com

Non-authoritative answer:
Name:    sohu.com
Addresses:  61.135.181.175, 61.135.181.176

当你冒充搜狐去新浪发信时,新浪从DNS上获得sohu的A记录,比较来访者ip 与A记录ip是否相同,相同不是冒充的,不同证明冒充

A 记录:当别人以邮箱服务器身份连接不要认证mx记录时候,需要从DNS中获得对方A记录,与来访者IP进行笔记,进行身份验证

***** 自己搭建一个邮件服务器,千万不要忘记去DNS上注册MX记录和A记录













































































猜你喜欢

转载自h496950806.iteye.com/blog/2059183