java接收邮件的探索之旅

场景:目前需要定时收取某个账户未读邮件,保存到elasticsearch doc中去。

使用javaMail收邮件主要有两种协议,一种是pop3,一种是imap。这两种协议都可以用来收邮件,但是在其中的处理上是有区别的。pop3是不支持判断邮件是否为已读的,也就是说你不能直接从收件箱里面取到未读邮件,这需要自己进行判断,然而imap就提供了这样的功能,使用imap时可以很轻松的判断该邮件是否为已读或未读或其他。
由此看来,pop3不适合我的需求【通过每次检索全部,然后判断subject也可以实现,不过每次都需要遍历对比,比较麻烦】
那么我就用imap协议来收取了,pop3和imap只是配置email的url有点区别 其他地方是一样的

pop3和imap主要区别就是能否判断邮件状态的问题,其他的操作都差不多.

准备工作:

邮箱设置打开pop3、imap、smtp收发协议

去你的126|163|qq邮箱 打开设置-pop3 如图
注意重点:

  • 全部接收,不然30天以前的收不到还以为代码有问题
  • 配置授权码,目前163和qq邮箱都是授权码形式,代码里的password位置填写的都是授权码不是邮箱密码
    enter description here

    协议的端口和协议规则

    //协议的内容端口等区别,对应关系如图:
    enter description here

具体的实现代码

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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
package cn.northpark.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;

/**
* @author github.com/liuhouer
* @有一封邮件就需要建立一个ReciveMail对象
*/
public class MailReceive {
private MimeMessage mimeMessage = null;
private String saveAttachPath = ""; //附件下载后的存放目录
private StringBuffer bodytext = new StringBuffer();//存放邮件内容
private String dateformat = "yy-MM-dd HH:mm"; //默认的日前显示格式

public MailReceive(MimeMessage mimeMessage) {
this.mimeMessage = mimeMessage;
}

public void setMimeMessage(MimeMessage mimeMessage) {
this.mimeMessage = mimeMessage;
}

/**
* 获得发件人的地址和姓名
*/
public String getFrom() throws Exception {
InternetAddress address[] = (InternetAddress[]) mimeMessage.getFrom();
String from = address[0].getAddress();
if (from == null)
from = "";
String personal = address[0].getPersonal();
if (personal == null)
personal = "";
String fromaddr = personal + "<" + from + ">";
return fromaddr;
}

/**
* 获得邮件的收件人,抄送,和密送的地址和姓名,根据所传递的参数的不同 "to"----收件人 "cc"---抄送人地址 "bcc"---密送人地址
*/
public String getMailAddress(String type) throws Exception {
String mailaddr = "";
String addtype = type.toUpperCase();
InternetAddress[] address = null;
if (addtype.equals("TO") || addtype.equals("CC")|| addtype.equals("BCC")) {
if (addtype.equals("TO")) {
address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.TO);
} else if (addtype.equals("CC")) {
address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.CC);
} else {
address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.BCC);
}
if (address != null) {
for (int i = 0; i < address.length; i++) {
String email = address[i].getAddress();
if (email == null)
email = "";
else {
email = MimeUtility.decodeText(email);
}
String personal = address[i].getPersonal();
if (personal == null)
personal = "";
else {
personal = MimeUtility.decodeText(personal);
}
String compositeto = personal + "<" + email + ">";
mailaddr += "," + compositeto;
}
mailaddr = mailaddr.substring(1);
}
} else {
throw new Exception("Error emailaddr type!");
}
return mailaddr;
}

/**
* 获得邮件主题
*/
public String getSubject() throws MessagingException {
String subject = "";
try {
subject = MimeUtility.decodeText(mimeMessage.getSubject());
if (subject == null)
subject = "";
} catch (Exception exce) {}
return subject;
}

/**
* 获得邮件发送日期
*/
public String getSentDate() throws Exception {
Date sentdate = mimeMessage.getSentDate();
SimpleDateFormat format = new SimpleDateFormat(dateformat);
return format.format(sentdate);
}

/**
* 获得邮件正文内容
*/
public String getBodyText() {
return bodytext.toString();
}

/**
* 解析邮件,把得到的邮件内容保存到一个StringBuffer对象中,解析邮件 主要是根据MimeType类型的不同执行不同的操作,一步一步的解析
*/
public void getMailContent(Part part) throws Exception {
String contenttype = part.getContentType();
int nameindex = contenttype.indexOf("name");
boolean conname = false;
if (nameindex != -1)
conname = true;
System.out.println("CONTENTTYPE: " + contenttype);
if (part.isMimeType("text/plain") && !conname) {
bodytext.append((String) part.getContent());
} else if (part.isMimeType("text/html") && !conname) {
bodytext.append((String) part.getContent());
} else if (part.isMimeType("multipart/*")) {
Multipart multipart = (Multipart) part.getContent();
int counts = multipart.getCount();
for (int i = 0; i < counts; i++) {
getMailContent(multipart.getBodyPart(i));
}
} else if (part.isMimeType("message/rfc822")) {
getMailContent((Part) part.getContent());
} else {}
}

/**
* 判断此邮件是否需要回执,如果需要回执返回"true",否则返回"false"
*/
public boolean getReplySign() throws MessagingException {
boolean replysign = false;
String needreply[] = mimeMessage
.getHeader("Disposition-Notification-To");
if (needreply != null) {
replysign = true;
}
return replysign;
}

/**
* 获得此邮件的Message-ID
*/
public String getMessageId() throws MessagingException {
return mimeMessage.getMessageID();
}

/**
* 【判断此邮件是否已读,如果已读返回false,未读返回true】
*/
public boolean isNew() throws MessagingException {
boolean isnew = true;
Flags flags = ((Message) mimeMessage).getFlags();
Flags.Flag[] flag = flags.getSystemFlags();
System.out.println("flags's length: " + flag.length);
for (int i = 0; i < flag.length; i++) {
if (flag[i] == Flags.Flag.SEEN) {
isnew = false;
System.out.println("seen Message.......");
break;
}
}
return isnew;
}

/**
* 判断此邮件是否包含附件
*/
public boolean isContainAttach(Part part) throws Exception {
boolean attachflag = false;
String contentType = part.getContentType();
if (part.isMimeType("multipart/*")) {
Multipart mp = (Multipart) part.getContent();
for (int i = 0; i < mp.getCount(); i++) {
BodyPart mpart = mp.getBodyPart(i);
String disposition = mpart.getDisposition();
if ((disposition != null)
&& ((disposition.equals(Part.ATTACHMENT)) || (disposition
.equals(Part.INLINE))))
attachflag = true;
else if (mpart.isMimeType("multipart/*")) {
attachflag = isContainAttach((Part) mpart);
} else {
String contype = mpart.getContentType();
if (contype.toLowerCase().indexOf("application") != -1)
attachflag = true;
if (contype.toLowerCase().indexOf("name") != -1)
attachflag = true;
}
}
} else if (part.isMimeType("message/rfc822")) {
attachflag = isContainAttach((Part) part.getContent());
}
return attachflag;
}

/**
* 【保存附件】
*/
public void saveAttachMent(Part part) throws Exception {
String fileName = "";
if (part.isMimeType("multipart/*")) {
Multipart mp = (Multipart) part.getContent();
for (int i = 0; i < mp.getCount(); i++) {
BodyPart mpart = mp.getBodyPart(i);
String disposition = mpart.getDisposition();
if ((disposition != null)
&& ((disposition.equals(Part.ATTACHMENT)) || (disposition
.equals(Part.INLINE)))) {
fileName = mpart.getFileName();
if (fileName.toLowerCase().indexOf("gb2312") != -1) {
fileName = MimeUtility.decodeText(fileName);
}
saveFile(fileName, mpart.getInputStream());
} else if (mpart.isMimeType("multipart/*")) {
saveAttachMent(mpart);
} else {
fileName = mpart.getFileName();
if ((fileName != null)
&& (fileName.toLowerCase().indexOf("GB2312") != -1)) {
fileName = MimeUtility.decodeText(fileName);
saveFile(fileName, mpart.getInputStream());
}
}
}
} else if (part.isMimeType("message/rfc822")) {
saveAttachMent((Part) part.getContent());
}
}

/**
* 【设置附件存放路径】
*/

public void setAttachPath(String attachpath) {
this.saveAttachPath = attachpath;
}

/**
* 【设置日期显示格式】
*/
public void setDateFormat(String format) throws Exception {
this.dateformat = format;
}

/**
* 【获得附件存放路径】
*/
public String getAttachPath() {
return saveAttachPath;
}

/**
* 【真正的保存附件到指定目录里】
*/
private void saveFile(String fileName, InputStream in) throws Exception {
String osName = System.getProperty("os.name");
String storedir = getAttachPath();
String separator = "";
if (osName == null)
osName = "";
if (osName.toLowerCase().indexOf("win") != -1) {
separator = "\\";
if (storedir == null || storedir.equals(""))
storedir = "c:\\tmp";
} else {
separator = "/";
storedir = "/tmp";
}
File storefile = new File(storedir + separator + fileName);
System.out.println("storefile's path: " + storefile.toString());
// for(int i=0;storefile.exists();i++){
// storefile = new File(storedir+separator+fileName+i);
// }
BufferedOutputStream bos = null;
BufferedInputStream bis = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(storefile));
bis = new BufferedInputStream(in);
int c;
while ((c = bis.read()) != -1) {
bos.write(c);
bos.flush();
}
} catch (Exception exception) {
exception.printStackTrace();
throw new Exception("文件保存失败!");
} finally {
bos.close();
bis.close();
}
}
/**
* 测试收邮件代码
*/
public static void main(String args[]) throws Exception {


Properties props = new Properties();

props.setProperty("mail.smtp.host", "smtp.126.com");//指定服务器

props.setProperty("mail.smtp.auth", "true");//指定需要验证

Session session = Session.getDefaultInstance(props);




//IMAP---------------------------------------------------------------------
URLName urln = new URLName("imap", "imap.126.com", 143, null, "用户名不还包含@126.com", "邮箱授权码");

//POP3---------------------------------------------------------
// URLName urln = new URLName("pop3", "pop3.126.com", 110, null, "test", "test");

Store store = session.getStore(urln);

store.connect();


Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
// 获取总邮件数
int total = folder.getMessageCount();
System.out.println("-----------------共有邮件:" + total + " 封--------------");
// 得到收件箱文件夹信息,获取邮件列表
System.out.println("未读邮件数:" + folder.getUnreadMessageCount());
Message messages[] = folder.getMessages();

MailReceive pmm = null;
for (int i = 0; i < messages.length; i++) {
System.out.println("======================");
pmm = new MailReceive((MimeMessage) messages[i]);
System.out.println("邮件 " + i + " 未读?: " + pmm.isNew());

if(pmm.isNew()){
// 获得邮件内容===============
pmm.getMailContent((Part) messages[i]);//把内容设置到bodytext
pmm.setAttachPath("d:\\");
pmm.saveAttachMent((Part) messages[i]);
System.out.println("Message " + i + " subject: " + pmm.getSubject());
System.out.println("Message " + i + " sentdate: "+ pmm.getSentDate());
System.out.println("Message " + i + " replysign: "+ pmm.getReplySign());
System.out.println("Message " + i + " containAttachment: "+ pmm.isContainAttach((Part) messages[i]));
System.out.println("Message " + i + " form: " + pmm.getFrom());
System.out.println("Message " + i + " to: "+ pmm.getMailAddress("to"));
System.out.println("Message " + i + " cc: "+ pmm.getMailAddress("cc"));
System.out.println("Message " + i + " bcc: "+ pmm.getMailAddress("bcc"));
pmm.setDateFormat("yy年MM月dd日 HH:mm");
System.out.println("Message " + i + " sentdate: "+ pmm.getSentDate());
System.out.println("Message " + i + " Message-ID: "+ pmm.getMessageId());
System.out.println("Message " + i + " 内容: "+ pmm.getBodyText());


//调接口存到es
}

}
}
}
生活不止苟且,还有我喜爱的海岸.