Java网络编程之JavaMail发送邮件和接受邮件
JavaMail是API 是一个标准的Java扩展,它是J2EE的范畴,在J2EE开发过程中可能会需要用到这个API。在学习JavaMail之前,有必须要对现在的互联网的邮件协议进行有个大体的了解。
邮件协议
在Internet中,常用的邮件操作相关的协议有3个—SMTP、POP、IMAP。
简单邮件传输协议(simple mail transferprotocol,SMTP),这个协议是邮件服务器之间相互发送邮件的协议,也是客户端利用该协议向邮件服务器端发送邮件的协议。一般一个邮件首先会被传送到某一个邮件服务器,再被邮件服务器分发到一个或多个目标邮件服务器。
邮局协议第3版(postoffice protocol version 3,POP3),协议主要用于从邮件服务器检索以得到新的邮件,大量的客户机从邮件服务器接收邮件就是使用POP3协议。
因特网消息访问协议(internet messager accessprotocol,IMAP),该协议比POP3功能更加强大,它可在接收邮件时,把邮件保存在邮件服务器中,既可在服务器中保留邮件也可把邮件下载
安装与配置JavaMail
由于JavaMail是一个扩展的部分,要进行发送接收邮件,需要两个包:
一个是JavaMail,这个包含了对SMTP、POP3、IMAP提供了支持,封装了电子邮件功能中的邮件对象、发送功能、身份认证、接收等。当前最新的版本是1.5
一个是JAF(JavaBeans Activation Framework),主要用来描述和显示邮件中的相关内容的,当前最新的版本是1.1.1
具体所需要的包,可以在本文的附件中直接下载。
邮件发送与接收
JavaMail包中的类比较多,主要用到的有会话类、地址类、邮件类、邮件发送类、邮件接收类和邮件文件夹类这些常用的类。
会话类(Session),主要用来创建邮件对象、实现邮件对象中数据的封装并可指定邮件服务器认证的客户端属性。它表示程序与某一个邮件服务器即将建立通信,在建立的过程可以进行口令认证。
地址类(Address),这个地址类主要是表示邮件发送人和邮件接收人的地址,一般主要用的是InternetAddress。
邮件类(Message),邮件消息的主要类,它包含了邮件中的所有部分,继承自一个接口Part,一般在使用的过程中直接是利用它的子类MimeMessage
邮件发送类(Transport),一般是从一个会话中获取一个邮件发送类的实例,将已经写好的邮件利用SMTP协议发送到指定的邮件服务器,在发送的过程中,首先根据指定口令连接到邮件服务器,再发送邮件。
邮件接收类(Store),这个其实就是邮件服务器中的存储库,里面放着所有的邮件文件夹
邮件文件夹类(Folder),该文件夹就是消息的具体所在文件夹,默认的邮件均在INBOX文件中。
发送邮件
基本步骤:
1 利用Properties来设置Session,一般主要设置两个mail.smtp.host和mail.smtp.auth,第一个主要是设置邮件服务器名,第二个是设置口令true或者false
2 利用Session.getInstance(Properties)启动一个与邮件服务器的连接
3 根据获取的Session来传建一个消息Message
4 定义消息的发信人地址InternetAddress和消息的收信人地址。
5 设置消息发送的主题和内容
6 利用Message.saveChanges()来存储填写的邮件信息
7 根据Session.getTransport("smtp")获取邮件发送类
8 利用发送人的用户名和密码连接到指定的邮件服务器
9 将该消息发送
注意:发送消息最重要的是要正确的找到发送消息的邮件服务器名,至于收信人的邮箱无所谓,可以是任意正确的邮件,譬如发送人是163邮件,可以发送给搜狐邮箱,新浪邮箱,QQ邮箱。
示例代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
package whut.mailsender;import java.util.Properties;import javax.activation.DataHandler;import javax.activation.FileDataSource;import javax.mail.Address;import javax.mail.BodyPart;import javax.mail.Message;import javax.mail.Multipart;import javax.mail.Session;import javax.mail.Transport;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeBodyPart;import javax.mail.internet.MimeMessage;import javax.mail.internet.MimeMultipart;import whut.mailreceiver.MailAuthenticator;public class SimpleSMTPSender public static void main(String[] try{ Propertiesnew Properties(); //传递一个邮件服务器名smtp.163.com //mail.smtp.host代表是发信人所在的邮箱服务器名 props.put("mail.smtp.host", "smtp.163.com"); props.put("mail.smtp.auth", true); //对于发送邮件,只需要保证发送人所在的邮件服务器正确打开就可以了 //收信人的邮箱可以是任意地址,如@163.com,@qq.com,@126.com //创建一个程序与邮件服务器的通信 Sessionnull); Messagenew MimeMessage(mailConnection); //创建一个要输入用户名和指令的 //Session //设置发送人和接受人 Addressnew InternetAddress("yyyy@163.com"); Addressnew InternetAddress("xxx@163.com"); /* * * * * * * * */ msg.setFrom(sender); msg.setRecipient(Message.RecipientType.TO, msg.setSubject("You); //msg.setContent("Hello", //下面是模拟发送带附件的邮件 //新建一个MimeMultipart对象用来存放多个BodyPart对象 Multipartnew MimeMultipart(); //------设置信件文本内容------ //新建一个存放信件内容的BodyPart对象 BodyPartnew MimeBodyPart(); //给BodyPart对象设置内容和格式/编码方式 mdp.setContent("hello","text/html;charset=gb2312"); //将含有信件内容的BodyPart加入到MimeMultipart对象中 mtp.addBodyPart(mdp); //设置信件的附件(用本地机上的文件作为附件) mdp=new MimeBodyPart(); FileDataSourcenew FileDataSource("f:/webservice.doc"); DataHandlernew DataHandler(fds); mdp.setFileName("webservice.doc");//可以和原文件名不一致 mdp.setDataHandler(dh); mtp.addBodyPart(mdp); //把mtp作为消息对象的内容 msg.setContent(mtp); //以上为发送带附件的方式 //先进行存储邮件 msg.saveChanges(); Transport"smtp"); String"yyyy@163.com"; String""; //邮件服务器名,用户名,密码 trans.connect("smtp.163.com", trans.sendMessage(msg, trans.close(); }catch(Exception { System.err.println(e); } finally{ System.exit(0); } }} |
接受邮件
基本步骤:
1 利用Properties创建一个属性,不需要设置任何属性,之间传递Session使用
2 Session.getDefaultInstance()获取一个邮件会话
3 使用该会话向某种提供者请求一个存储库,ss.getStore("pop3");获取一个Store
4 存储库向指定的邮件服务器建立连接
5 通过getFolder("INBOX"),获取该存储库中INBOX文件夹
6 打开INBOX文件夹
7 消息处理
8 关闭文件夹
9 关闭存储库
注意:从服务器返回的邮件有可能在发送者或者接受者出现中文乱码,这里进行了乱码处理
示例代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package whut.mailreceiver;import java.io.InputStreamReader;import java.io.Reader;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Enumeration;import java.util.Properties;import javax.mail.Flags;import javax.mail.Folder;import javax.mail.Header;import javax.mail.Message;import javax.mail.Session;import javax.mail.Store;import javax.mail.internet.InternetAddress;import javax.mail.internet.MimeUtility;//利用POP3来读取邮件//主要用来检测消息Message的基本信息,如发送者,收信者,时间public class POP3Client public static void main(String[] Properties String"pop3.163.com"; String"22222222@163.com"; String"312313121"; String"pop3"; try { // Sessionnull); // Store // store.connect(host, // // Folder"INBOX"); if (inboxnull) System.out.println("NO); System.exit(1); } // inbox.open(Folder.READ_ONLY); System.out.println("TOTAL + // Message[] for (int i0; System.out.println("------------Message--" +1) + "------------"); // String if (fromnull) String System.out.println("From:" + } String .getReplyTo()); if (replyTonull) { String System.out.println("Reply + } String .getRecipients(Message.RecipientType.TO)); if (tonull) String System.out.println("To:" + } String if (subjectnull) System.out.println("Subject:" + SimpleDateFormatnew SimpleDateFormat( "yyyy-MM-dd); Date if (sentnull) System.out.println("Sent + Date if (ressnull) System.out.println("Receive + // // // // // // // // // // // // // // // // // // // // // // // // // // // } // // inbox.close(false); store.close(); } catch (Exception System.err.println(e); } } // public static String String try { if (from.startsWith("=?GB")"=?gb") ||"=?UTF")) from } else { fromnew String(from.getBytes("ISO8859_1"), "GBK"); } } catch (Exception e.printStackTrace(); } return from; }} |
一般在读取邮件的时候会有个口令验证,可以在访问的过程中设置用于用户口令输入提示框:此时要修改一下Session的获取方法,传递一个继承了Authenticator,连接到POP3服务器,当提供者需要用户名和密码的时候,则会回调Authenticator的子类的getPasswordAuthentication必,同时须在connect中口令字段为null才能行
Session ss=Session.getDefaultInstance(props, new MailAuthenticator());
//向回话请求一个某种提供者的存储库,是一个POP3提供者
Store store=ss.getStore(provider);
//连接存储库,从而可以打开存储库中的文件夹,此时是面向IMAP的store.connect(host, null, null);
口令弹出框代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
package whut.mailreceiver;import java.awt.Container;import java.awt.GridLayout;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.mail.Authenticator;import javax.mail.PasswordAuthentication;import javax.swing.JButton;import javax.swing.JDialog;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JPasswordField;import javax.swing.JTextField;//口令验证public class MailAuthenticator extends Authenticator private JDialognew JDialog(new JFrame(),true); private JLabelnew JLabel("Please); private JLabelnew JLabel("User); private JLabelnew JLabel("Password:"); private JTextFieldnew JTextField(20); private JPasswordFieldnew JPasswordField(20); private JButtonnew JButton("OK"); public MailAuthenticator() { this(""); } public MailAuthenticator(String { Container pane.setLayout(new GridLayout(4,1)); pane.add(mainLabel); JPanelnew JPanel(); p2.add(userLabel); p2.add(usernameField); pane.add(p2); JPanelnew JPanel(); p3.add(passwordLabel); p3.add(passwordField); pane.add(p3); JPanelnew JPanel(); p4.add(okButton); pane.add(p4); passwordDialog.setSize(400, 200); ActionListenernew HideDialog(); okButton.addActionListener(al); usernameField.addActionListener(al); passwordField.addActionListener(al); } class HideDialog implements ActionListener { public void actionPerformed(ActionEvent { passwordDialog.hide(); } } @Override protected PasswordAuthentication // passwordDialog.show(); //getPassword是返回的字符数组 String Stringnew String(passwordField.getPassword()); passwordField.setText(""); return new PasswordAuthentication(username,password); }} |
邮件传输中的几个类说明
Addres类,一般直接使用它的子类InternetAddress邮箱的地址,有两个特别重要的方法toString(),y用于将地址数组转换为字符串,并且多个地址以逗号隔开,parse()用于将以逗号隔开的地址解析为地址数组,这个可以为群发邮件用。
URLName类,这个目的是为了构造一个不需要该模式的协议处理器,它不会尝试连接,可以用于方便的标识文件夹和非标准的URL的存储库
Message类,主要是消息的抽象类,一般使用其子类MimeMessage,可以通过它来获取邮件的发送者,接受者,时间,主题,内容等邮件首部,查看邮件查收情况。
Part接口,一般包括了部分属性的方法、首部的方法、和内容的方法。实际运用中都是通过它的子类来调用的,可以根据属性来判断一个邮件是否含有附件。利用getAllHeaders()获得邮件的所有首部名和值,它返回的是Enumeration。
查看邮件的内容,查看MIME内容的类型是getContentType(),如返回"text/plain;charset="GBK",
一般通过getContent()来查看返回具体的内容,这里利用了JAF来自动的调整类型为java可识别的类型,当是text/plain的时候,返回是String,内容是多部分的时候,返回的是Multipart对象。如果是其他JAF也会将其转换为Java适当的对象。如果类型不能识别,则返回一个InputStream。
写入邮件的内容,一般文本型直接调用setText();也可以使用setContent(string,chartype);当要发送多个部分的时候,就需要setContent(Multipart p);每一个部分必须是MimeBodyPart,然后将其添加到MimeMultipart.在邮件的传输过程中,如果想要传输文件的话,必须将数据包装到BodyPart中,然后再添加到Multipart
中。
Folder文件,一般都是通过Session、Store或另一个Folder获得,一般获取的文件夹并不确保一定存在,要利用exists()判断。对于文件夹的一些操作必须要注意,检索和获取文件夹信息,必须要打开文件夹上才能操作。删除或者重命名文件夹,只能在文件夹关闭的时候完成。
题外:
国内常见的几个免费邮件服务器名如下:
网易免费邮箱:发送服务器:smtp.163.com 接收服务器:pop.163.com
新浪免费邮箱:发送服务器:smtp.sina.com.cn 接收服务器:pop3.sina.com.cn
搜狐邮箱:发送服务器:smtp.sohu.com 接收服务器:pop3.sohu.com
常见乱码处理方式
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
package whut.mailsender;import javax.mail.Part;import javax.mail.internet.MimeUtility;import sun.misc.BASE64Decoder;public class StringUtil //发信人,收信人,回执人邮件中有中文处理乱码,res为获取的地址 //http默认的编码方式为ISO8859_1 //对含有中文的发送地址,使用MimeUtility.decodeTex方法 //对其他则把地址从ISO8859_1编码转换成gbk编码 public static String String try { if (from.startsWith("=?GB")"=?gb") ||"=?UTF")) from } else { fromnew String(from.getBytes("ISO8859_1"), "GBK"); } } catch (Exception e.printStackTrace(); } return from; } //转换为GBK编码 public static String try { if (strvaluenull) return null; else { strvaluenew String(strvalue.getBytes("ISO8859_1"), "GBK"); return strvalue; } } catch (Exception return null; } } //接收邮件时,获取某个邮件的中文附件名,出现乱码 //对于用base64编码过的中文,则采用base64解码, //否则对附件名进行ISO8859_1到gbk的编码转换 public static Stringthrows Exception String// if ((temp.startsWith("=?GBK?")"?=")) ||"=?gbk?b?")"?="))) temp8,"?=")1)); } else { temp } return temp; } public static String if (snull) return null; BASE64Decodernew BASE64Decoder(); try { byte[] return new String(b); } catch (Exception return null; } }} |
本文出自 “在云端的追梦” 博客,请务必保留此出处http://computerdragon.blog.51cto.com/6235984/1197390
Java网络编程之JavaMail发送邮件和接受邮件的更多相关文章
- Java网络编程之TCP、UDP
Java网络编程之TCP.UDP 2014-11-25 15:23 513人阅读 评论(0) 收藏 举报 分类: java基础及多线程(28) 版权声明:本文为博主原创文章,未经博主允许不得转载. ...
- Java网络编程之UDP
Java网络编程之UDP 一.C/S架构中UDP网络通信流程 ①创建DatagramSocket与DatagramPacket对象 ②建立发送端,接收端 ③建立数据包 ④调用Socket的发送.接收方 ...
- Java网络编程之URLConnection
Java网络编程之URLConnecton 一.URLConnection简介 URLConnection是一个抽象类,表示指向URL指定资源的活动连接.URLConnection有两个不同但相关的用 ...
- Java网络编程之URL和URI
Java网络编程之URL与URI 一.URL与URI简介 URI = Universal Resource Identifier 统一资源标志符 URL = Universal Resource Lo ...
- Java网络编程之InetAddress浅析
Java网络编程之InetAddress浅析 一.InetAddress综述 IP地址是IP使用的32位(IPv4)或者128位(IPv6)位无符号数字,它是传输层协议TCP,UDP的基础.InetA ...
- Java网络编程之TCP
Java网络编程之TCP TCP主要需要两个类:Socket和ServerSocket,Socket是客户端连接服务器时创建,参数需要指定服务器的ip和端口,ServerSocket是服务器端创建 ...
- java网络编程之TCP通讯
java中的网络编程之TCP协议的详细介绍,以及如何使用,同时我在下面举2例说明如何搭配IO流进行操作, /* *TCP *建立连接,形成传输数据的通道: *在连接中进行大数据量传输: *通过三次握手 ...
- 使用JavaMail发送邮件和接受邮件
转载:http://blog.csdn.net/zdp072/article/details/30977213 一. 为什么要学习JavaMail 为什么要学习JavaMail开发? 现在很多WEB应 ...
- 3.Java网络编程之IP
前面两篇博文我们已经简单了解了IP.端口.协议以及两种参考模型,我们现在重新从程序角度来看下这个参考模型. 如果我们从事的是Web网站开发,那么我们应该知道HTML是一种超文本标记语言 (Hyper ...
- java网络编程之UDP通讯
详细介绍了java中的网络通信机制,尤其是UDP协议,通过对UDP的基本使用进行举例说明如何使用UDP进行数据的发送接收,并举了两个小demo说明UDP的使用注意事项. UDP协议原理图解: UDP协 ...
随机推荐
- Docker网络下-自定义网络实战
通过前面两篇的学习,我们对docker网络及四大网络类型都了解了.本文,咱们就来学习docker的自定义网络.我们为什么需要自定义网络呢?是为了让各个主机分门别类,井井有条.方便关联,使得网络之间可以 ...
- Java 集合工具包
Java 集合工具包 Java集合是java提供的工具包,包含了常用的数据结构:集合.链表.队列.栈.数组.映射等. Java集合工具包位置是java.util.* Java集合主要可以划分为4个部分 ...
- C++: 如何高效地往unordered_map中插入key-value
C++: unordered_map 花式插入key-value的5种方式 前言 无意中发现std::unordered_map.std::map等插入key-value对在C++17后竟有了 ins ...
- vue 实现组件全屏展示及退出
vue 实现组件全屏展示及退出 一.组件 采用 vue-fullscreen 组件 二.实现方式 <fullscreen ref="fullscreen" @change=& ...
- 前端项目通过 Nginx 发布至 Linux,并通过 rewrite 配置访问后端接口
〇.前言 本文通过将 arco 框架的前端项目,部署至 CentOS 7,并访问同服务器的 WebAPI 接口,来简单演示一下,如何将前端项目发布至 Linux 系统. 关于 ASP.NET WebA ...
- SpringBoot配置多个数据源-详解
一直在趟坑,从未被超越. 借鉴文章 个人觉得我算是整理的比较详细的了,有些博客老是缺斤少两的.最恶心的是竟然会有人写到,如需下文请关注什么什么公众号. 结构 pom文件 <dependencie ...
- 高通ramdump
背景 高通平台下提供了一个工具,专门用来抓取内核死机以后的dump信息.如果只是非系统层面的crash(例如底层应用,安卓程序),则不能抓取dump信息. 在阅读一些文档的时候知道有这个功能,但是一直 ...
- Android内存分析命令
一.内存指标 Item 全称 含义 等价 USS Unique Set Size 物理内存 进程独占的内存 PSS Proportional Set Size 物理内存 PSS= USS+ 按比例包含 ...
- /proc/pids/smaps
Linux内存管理 -- /proc/{pid}/smaps讲解 基本介绍 /proc/PID/smaps 文件是基于 /proc/PID/maps 的扩展,他展示了一个进程的内存消耗,比同一目录下的 ...
- 2022年第十八届 GOPS 全球运维大会资料分享
全球运维大会是国内第一个运维行业大会,面向互联网.金融.通信及传统行业广大运维技术人员,旨在传播先进技术思想和理念,分享业内最佳实践. 2022年第十八届 GOPS 全球运维大会(深圳站)共分为18个 ...