码迷,mamicode.com
首页 > 编程语言 > 详细

关于javamail的一些笔记

时间:2015-05-14 14:25:15      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:javamail   邮件服务器   base64   邮件   激活邮件   

1.为什么要学习javamail?

企业中系统 经常需要信息通知 和 信息校验

2.利用telnet实现邮件收发

注册sina和sohu账户
yuyang94895@sina.com
yuyang94895@sohu.com
密码:1qaz2wsx

将用户名和密码加密,加密使用Base64Util 类

package cn.itcast.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import sun.misc.BASE64Encoder;
public class Base64Util 
{
	public static void main(String args[]) throws IOException
	{
		System.out.print("请输入用户名:");
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		String userName = in.readLine();
		System.out.print("请输入密码:");
		String password = in.readLine();
		BASE64Encoder encoder = new BASE64Encoder();
		System.out.println("编码后的用户名为:" 
				+ encoder.encode(userName.getBytes()));
		System.out.println("编码后的密码为:" 
				+ encoder.encode(password.getBytes()));		
	}
}


编码后的用户名为:eXV5YW5nOTQ4OTU=

编码后的密码为:MXFhejJ3c3g=


使用telnet的流程

打开cmd,使用telnet命令   smtp.sina.com
ehlo xxx
auth login
eXV5YW5nOTQ4OTU=
MXFhejJ3c3g=
mail from:<yuyang94895@sina.com>
rcpt to:<yuyang94895@sina.com>
data
一封测试邮件。
.
quit


发送邮件服务 smtp.sina.com


邮件正文需要一定格式的?RFC822要求 标准格式邮件
ehlo xxx
auth login
eXV5YW5nOTQ4OTU=
MXFhejJ3c3g=
mail from:<yuyang94895@sina.com>
rcpt to:<yuyang94895@sohu.com>
data


from:<yuyang94895@sina.com>
to:<yuyang94895@sohu.com>
subject:测试邮件
一封测试邮件。
.
quit


----------------------------------------------------------
收邮件 pop3协议格式    telnet  pop3.sohu.com
user 用户名
pass 密码
stat (查看所有邮件总和信息)
list 邮件编号 (查看某封邮件大小)
retr 邮件编号 (查看邮件内容)


企业实际中,通常需要使用收邮件客户端 收取邮件 outlook 和 foxmail


区分:smtp、pop3 、RFC822 、MIME
smtp、pop3 ----- 邮件传输协议
RFC822、MIME ----- 邮件正文格式



-----------------------------------------------------------
RFC822 漏洞
mail from:<yuyang94895@sina.com> 真正发件人
from:<yuyang94895@sina.com> 仅是正文中,显示发件人信息
篡改from字段,冒充别人发邮件


ehlo xxx
auth login
YWFh
MTIz
mail from:<aaa@estore.com>
rcpt to:<bbb@estore.com>
data


from:<hr@google.com>
to:<bbb@estore.com>
subject:入职通知


您已被google录取,年薪30万,下周一(2012.3.12) 正式入职。
.
quit


------------------------------------------------------------





通过nslookup

set type=mx
sina.com
查询所有新浪mx记录 ----- 这些邮件服务器不需要用户名和密码校验
freemx3.sinamail.sina.com.cn


ehlo xxx
mail from:<hr@google.com>
rcpt to:<yuyang94895@sina.com>
data


from:<hr@google.com>
to:<yuyang94895@sina.com>
subject:测试邮件2
一封测试邮件2。
.
quit
----------------------------- 结果失败!!!

MX记录和A记录的作用:

1.  A记录:WEB服务器的IP指向(IP是固定的,怎么样都不变,域名是变化的
     A (Address) 记录是用来指定主机名(或域名)对应的IP地址记录。
   说明:用户可以将该域名下的网站服务器指向到自己的web server上。同时也可以设置自己域名的二级域名。
   就是说:通过A记录,大家可以设置自己的不同域名转到不同的IP上去!如:
   
   www.yourname.com 转到IP 321.32.321.321
   ftp.yourname.com 转到IP 123.12.123.123
   mail.yourname.com 转到IP 213.21.213.213

2.MX记录(Mail Exchange):邮件路由记录
   说明:用户可以将该域名下的邮件服务器指向到自己的mail server上,然后即可自行操作控制所有的邮箱设置。您只需在线填写您服务器的主机名或主机IP地址,即可将您域名下的邮件全部转到您自己设定相应的邮件服务器上。
这个大家都明白了吗?就是将你的域名中邮件服务器分开,将它设置到其它的IP去!
比如同样是 myweb.com ,如果你设置A记录是指向123.12.123.123,而MX记录你设置是指向222.22.222.222,那么你的DNS服务器接收到别人的邮件路 由请求时就将会将它的请求解释到222.22.222.222上去!而别人访问你的网页的时候仍然是访问123.12.123.123。



JavaMail

MIME协议描述一封邮件



ContentType:text/html(html网页) ------ content-type:text/plain(纯文本)
邮件正文
这是一张图片<img src="cid:mypic" /> , 该图片是xxx
--------------------------------------------------------------
Content-Type:image/jpeg
Content-Disposition: inline
Content-id:mypic
邮件图片
--------------------------------------------------------------
Content-Disposition: attachment
附件
--------------------------------------------------------------


content-id为每个部分起一个唯一标识 ----------------------- 用于引用
Content-Type: 指定数据类型
Content-Disposition: 指定数据阅读处理方式:inline attachment



JavaMail API
邮件是用 Message 来表示的
MIME是不是一个复杂邮件,有很多部分组成 每一个部分就是一个part


BodyPart
Message
Multipart



java.lang.NoClassDefFoundError: com/sun/mail/util/LineInputStream 异常 解决?

主要原因是: 

 javax.mail和javax.activation这两个包已经在javaEE5当中属于基础包了,就是JDK中自带了已经,但是里面的方法与现在外面的mail.jar和activation.jar有一些出入,所以初学者在直接copy别人代码的时候往往会出现上面的错误。 

废话不多说下面是解决方法 
进到

X:/Program Files/MyEclipse 6.5/myeclipse/eclipse/plugins/com.genuitec.eclipse.j2eedt.core_6.5.0.zmyeclipse650200806/data/libraryset/EE_5

这个路径里,可以看到javaee.jar,用rar把这个文件打开,然后进到javax文件夹里,删除mail.jar和activation.jar(我的javaee.jar里,这两个东西是文件夹,总之删掉就OK,不过要注意备份一下)

删掉之后运行下面的代码,经行简单的修改以后就可以实现接收邮件的功能了!




依赖jar包中 javamail jaf(java activation framework) ---- javamail 依赖jaf
JDK6.0开始 引入jaf
** 如果使用JDK5.0 包括之前版本,使用javamail时 需要手动引入jaf


复杂邮件内容直接关系
邮件中一块数据 ------ BodyPart
当两块数据合并时 ----- MultiPart(并不表示是一块数据) ------ BodyPart
Message代表整封邮件,Message相当于一个大的BodyPart


---------------------------------------------------------------------------------

JavaMail设计邮件案例

1、编写最简单邮件(邮件内容是文本内容) from to subject  ---- setText
2、编写复杂邮件 原理 :每个页面中的部分 对应 MimeBodyPart
当两个BodyPary 合并到一起时 ,需要MultiPart ----- setSubType(设置邮件部分之间组合方式)
3、编写带有嵌入图片邮件
* 为图片BodyPart 设置Content-id, 在邮件正文中 通过cid引用
4、编写带有附件邮件
* 在建立附件时,设置附件名称(注意中文转码 MimeUtility )


乱码问题:

1、正文中乱码 text/html;charset=utf-8;

2、附件名乱码 MimeUtility.encodeText

如  attachment.setFileName(MimeUtility.encodeText("因为爱情.mp3"));


如何书写复杂邮件:


@Test
	public void demo() throws AddressException, MessagingException,
			FileNotFoundException, IOException {
		// 编写 嵌入图片 携带附件 邮件
		// 包含附件的邮件
		Properties props = new Properties();// 发送邮件、接收邮件
		Session session = Session.getDefaultInstance(props);
		// 编写嵌入图片的邮件
		Message message = new MimeMessage(session);

		// 所有邮件必须信息
		message.setFrom(new InternetAddress("aaa@estore.com"));
		message.setRecipient(RecipientType.TO, new InternetAddress(
				"bbb@estore.com"));
		message.setSubject("这是一个包含附件和嵌入图片的邮件");

		// 编写邮件正文
		MimeBodyPart content = new MimeBodyPart();
		content.setContent("该邮件既有图片 又有附件!图片<img src='cid:mypic'/>",
				"text/html;charset=utf-8");

		MimeBodyPart pic = new MimeBodyPart();
		DataHandler dh1 = new DataHandler(new FileDataSource("mm.jpg"));
		pic.setDataHandler(dh1);
		pic.setContentID("mypic");

		MimeBodyPart attachment = new MimeBodyPart();
		DataHandler dh2 = new DataHandler(new FileDataSource("love.mp3"));
		attachment.setDataHandler(dh2);
		attachment.setFileName(MimeUtility.encodeText("因为爱情.mp3"));

		// 整合
		MimeMultipart m1 = new MimeMultipart();
		m1.addBodyPart(content);
		m1.addBodyPart(pic);
		m1.setSubType("related");

		MimeBodyPart temp = new MimeBodyPart();
		temp.setContent(m1);

		// 继续整合
		MimeMultipart m2 = new MimeMultipart();
		m2.addBodyPart(temp);
		m2.addBodyPart(attachment);
		m2.setSubType("mixed");

		message.setContent(m2);
		message.writeTo(new FileOutputStream("c:\\测试用复杂邮件.eml"));
	}


------------------------------------------------------------------------------------

真实案例:注册后激活邮件案例

注册功能、登陆功能 
激活邮件原理是什么?
原理:在用户注册的时候,保存用户信息到数据库 同时,在数据库里面添加两个字段 一个字段是否激活、另一个字段存放激活码,激活过期时间


设计数据表

id   username   password   email    active    activeCode    expiresActionDate

编写登陆页面(login.jsp),注册页面(regist.jsp),注册成功页面(regist_success.jsp)(略)

vo类中将上述所有属性建立set  get方法

registServlet的编写方法

package cn.servlet;

import java.io.IOException;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.dbutils.QueryRunner;

import cn.itcast.mail.SendMail;
import cn.itcast.utils.JDBCUtils;
import cn.itcast.utils.UUIDUtils;
import cn.itcast.vo.User;

public class RegistServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		// 获得客户端数据
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		String email = request.getParameter("email");

		String activeCode = UUIDUtils.generatedActiveCode();
		long now = System.currentTimeMillis();
		long expires = now + 1000 * 60 * 60 * 24;
		// datetime yyyy-MM-dd hh:mm:ss
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		String expiresActiveDate = dateFormat.format(new Date(expires));

		// 编写DBUtils存储程序
		String sql = "insert into user values(null,?,?,?,?,?,?)";
		// 0 表示未激活 1表示激活
		Object[] param = { username, password, email, "0", activeCode,
				expiresActiveDate };
		QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
		try {
			queryRunner.update(sql, param);
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}

		// 发送激活邮件,为了不让用户等待,开启一个独立线程发送
		User user = new User();
		user.setUsername(username);
		user.setPassword(password);
		user.setExpiresActiveDate(expiresActiveDate);
		user.setActiveCode(activeCode);
		user.setEmail(email);

		// 开启独立线程(防止用户等待时间过长)
		new Thread(new SendMail(user)).start(); // 发邮件

		request.getRequestDispatcher("/regist_success.jsp").forward(request,
				response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

然后编写自动发送激活邮件的程序代码:

package cn..mail;

import java.util.Properties;

import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.Message.RecipientType;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import cn.itcast.vo.User;

public class SendMail implements Runnable {

	private User user;

	public SendMail(User user) {
		this.user = user;
	}

	@Override
	public void run() {
		// 建立Session
		Properties properties = new Properties();
		properties.setProperty("mail.smtp.host", "localhost");
		properties.setProperty("mail.transport.protocol", "smtp");
		Session session = Session.getDefaultInstance(properties);
		// 编写Message
		Message message = new MimeMessage(session);
		try {
			// 设置发件人
			message.setFrom(new InternetAddress("aaa@estore.com"));
			// 设置收件人
			message.setRecipient(RecipientType.TO, new InternetAddress(user
					.getEmail()));
			// 设置邮件主题
			message.setSubject("estore商城激活邮件");
			// 设置内容
			message
					.setContent(
							"<h4>欢迎使用estore商城系统,您的用户名是"
									+ user.getUsername()
									+ ",您的密码是"
									+ user.getPassword()
									+ ",请妥善保管。</h4><h4>请于"
									+ user.getExpiresActiveDate()
									+ "之前点击下面链接激活账号,否则账号将被删除!</h4><h3><a href='http://localhost/day20_mail/active?activeCode="
									+ user.getActiveCode()
									+ "'>http://localhost/day20_mail/active?activeCode="
									+ user.getActiveCode() + "</a></h3>",
							"text/html;charset=utf-8");
			// 通过Transport发送
			Transport transport = session.getTransport();
			transport.connect("aaa", "123");
			transport.sendMessage(message, message.getAllRecipients());
		} catch (AddressException e) {
			e.printStackTrace();
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}

}

编写登陆的LoginServlet

package cn.servlet;

import java.io.IOException;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import cn.itcast.utils.JDBCUtils;
import cn.itcast.vo.User;

public class LoginServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		String username = request.getParameter("username");
		String password = request.getParameter("password");

		String sql = "select * from user where username=? and password = ?";
		QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());

		try {
			User user = queryRunner.query(sql,
					new BeanHandler<User>(User.class), new Object[] { username,
							password });
			if (user == null) {
				// 登陆失败
				request.getRequestDispatcher("/login.jsp").forward(request,
						response);
			} else {
				// 判断账号是否激活
				if (user.getActive().equals("0")) {
					response.getWriter().println("对不起,账户未激活,请赶快查收邮件激活!");
				} else {
					response.getWriter().println("用户登陆成功!");
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

编写激活邮件激活账号(操作数据库)代码

package cn.servlet;

import java.io.IOException;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;

import cn.itcast.utils.JDBCUtils;
import cn.itcast.vo.User;

public class ActiveServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 获得激活码
		String activeCode = request.getParameter("activeCode");
		response.setContentType("text/html;charset=utf-8");

		// 到数据库查找激活码对应数据
		String sql = "select * from user where activeCode = ?";
		QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());
		try {
			User user = queryRunner.query(sql,
					new BeanHandler<User>(User.class), activeCode);
			if (user == null) {
				// 激活码无效
				response.getWriter().println("您输入的激活码无效,可能因为账号过期 未激活,系统已经删除!");
			} else {
				// 激活码有效
				// 判断是否过期
				String date1 = user.getExpiresActiveDate();
				DateFormat dateFormat = new SimpleDateFormat(
						"yyyy-MM-dd hh:mm:ss");
				long expires = dateFormat.parse(date1).getTime();
				long now = System.currentTimeMillis();
				if (expires > now) {
					// 没过期
					// 操作数据库
					String updateSql = "update user set active='1' where id=?";
					queryRunner.update(updateSql, user.getId());
					response.getWriter().println("账号激活成功!");
				} else {
					// 激活过期
					response.getWriter().println("激活时间已过期,请重新注册!");
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		} catch (ParseException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}

编写用Base64Util加密的UUID类(激活邮件时使用)

package cn.utils;

import java.util.UUID;

import sun.misc.BASE64Encoder;

public class UUIDUtils {
	public static String generatedActiveCode() {
		UUID uuid = UUID.randomUUID();
		BASE64Encoder base64Encoder = new BASE64Encoder();
		return base64Encoder.encode(uuid.toString().getBytes());//加密UUID的代码
	}

	public static void main(String[] args) {
		System.out.println(UUIDUtils.generatedActiveCode());
	}
}

上述代码即为编写激活邮件的后端实现






JavaMail技术很多服务器都是支持的 ---- Tomcat(内置javamail使用方法)



配置<Context>元素,配置JavaMail服务(3种方法)
1、配置server.xml <Host>元素中配置Context元素  ---- 对当前工程有效
2、配置context.xml 配置Tomcat连接池  ---- 对于tomcat服务器中所有web工程都有效
3、在web工程下META-INFO/context.xml ---- 对当前工程有效



java类加载器机制
同一个类 被不同类加载器分别加载,会认为不是一个类


*同过tomcat配置JavaMail的Session 通过JNDI方式访问 -------- 类加载器问题
package cn.servlet;

import java.io.IOException;

import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.Message.RecipientType;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JNDIMailServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		try {
			// 获得session
			Context initCtx = new InitialContext();
			Context envCtx = (Context) initCtx.lookup("java:comp/env");
			Session session = (Session) envCtx.lookup("mail/Session");

			// 编写最简单邮件
			Message message = new MimeMessage(session);
			message.setFrom(new InternetAddress("aaa@estore.com"));
			message.setRecipient(RecipientType.TO, new InternetAddress(
					"bbb@estore.com"));
			message.setSubject("JNDI测试邮件");
			message.setText("JDNI测试内容");

			Transport transport = session.getTransport();
			transport.connect("aaa", "123");
			transport.sendMessage(message, message.getAllRecipients());

		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}

	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doGet(request, response);
	}

}
























































































































关于javamail的一些笔记

标签:javamail   邮件服务器   base64   邮件   激活邮件   

原文地址:http://blog.csdn.net/qhwc2009/article/details/45718195

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!