讲到android的邮件收发,首先就要讲讲关于邮件协议的一下基础,度娘基本都有,这里是怕自己忘记,贴点备忘录。
现在常用的电子邮件协议有SMTP(25)、POP3(110)、IMAP4(143)。他们都处于TCP/IP协议簇,还包括他们的加密协议,SMTPS(465)、POPS(995)、IMAPS(993),他们的默认端口号都在后面的小括号里面了。其中的细节就不讲了,SMTP协议负责发送邮件,而POP3及IMAP4协议则负责接收邮箱里面的邮件,而IMAP协议则是一种优于POP的新协议,他克服了POP的一些缺点。例如,他可以决定客户端请求邮件服务器提交所受到邮件的方式,请求邮件服务器只下载所选中的这个邮件等。他可以使用户很好的在服务器上管理自己的邮箱,完成这些工作也不需要把邮件从服务器上下载下来。其中还牵扯到了另一个协议(MIME),在里面定义了传输邮件的邮件体内部协议。
首先在编写代码时需要导入JAR包:http://download.csdn.net/detail/github_34437042/9597713(其中有个bcprov的包是用来接受加密类型的)。
1.发送邮件
在发送邮件上并没有太大的问题,因为给出的协议就一种。在发送邮件之前需要先进行设置服务器主机,用户验证,登陆账号,创建会话并得到邮件发送对象。
// 系统属性
Properties properties = System.getProperties();
// 设置主机
properties.put("mail.smtp.host", "发件服务器");
// 身份确认
properties.put("mail.smtp.auth", "true");
// 用户名,密码登陆
PopupAuthenticator popupAuthenticator = new PopupAuthenticator();
// 得到邮件回话对象
Session session = Session.getDefaultInstance(properties, popupAuthenticator);
session.setDebug(true);
// 得到邮件对象
Message message = new MimeMessage(session);
其中需要登陆账户:
public class PopupAuthenticator extends Authenticator {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("你的邮箱账户", "你的邮箱密码");
}
}
在整个确认用户的过程中都是异步运行,所以要进行特殊处理。完成上面的代码之后就可以往message邮件中添加自己想放的数据作为一个邮件发送出去就行了,但是在发送之前我们需要知道发送数据的几种类型(只有邮件主要内容)要特殊处理。虽然现在你可能发现在自己的message后面可以setText()发送自己想要发送的主体内容了。
以上是邮件发送及接受都需要知道的几个特殊类:Message(这是javamail中的类,不是os中的)、InternetAddress(发件人,收件人,抄送人,好像还有一个密送人都放在这些属于自己的该类数组)、Multiple(一个数据容器)、BodyPart(存放各种数据的对象容器)。就像图片中看到的内容一样,邮件的内容是层层包裹后发送的,当然这只是其中发送数据的一种方式,称之为"multipart/*"的复杂体邮件,这类邮件中可以存放附件。这些类型的分类在接收并解析邮件内容时才还会详解。因为我们不需要知道发送的类型,只需要知道是否发送成功就行了。
try {
// 主题
message.setSubject(theme.getText().toString());
// 以text方式发送 内容
// message.setText();
// 发件人地址
message.setFrom(new InternetAddress(adresseeString));
// 现将数据转换为数组后添加收件人地址
InternetAddress[] addressesArray = new InternetAddress[toList.size()];
toList.toArray(addressesArray);
message.addRecipients(Message.RecipientType.TO,addressesArray);
// 现将数据转换为数组后添加抄送人地址
if (ccList.size() > 0) {
InternetAddress[] ccsArray = new InternetAddress[ccList.size()];
ccList.toArray(ccsArray);
message.addRecipients(Message.RecipientType.CC,ccsArray);
}
// 发送带有附件的邮件
message = MailUtils.sendMessageBodyPart(message,content.getText().toString(), new Date(),pathList, pathNameList);
// 设置邮件支持多种格式
MailUtils.sendAndCollect();
message.saveChanges();
// 发送邮件
Transport.send(message);
} catch (AddressException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
在复制代码的时候我看着自己的代码都凌乱了,真心看不懂。
首先需要知道message接收各种人的时候需要的是数组,但是我一开始用集合是因为添加和删除比较方便,并在用户发送邮件的时候转换一下就可以了。(from-发件人,to-收件人,cc-抄送人,bcc-密送人)
以下是发送带附件邮件的方法代码,其中我们需要知道用户书写的文本数据,附件路径集合,附件名称集合,这些需要自己完成打开文件夹并点击找到该文件的路径并返回给编写邮件的activity添加到集合中
// 发送带有附件的邮件
public static Message sendMessageBodyPart(Message message, String text,
Date time, List pathList, List pathNameList)
throws MessagingException {
// 时间
message.setSentDate(new Date());
// multipart格式邮件
Multipart multipart = new MimeMultipart();
BodyPart bodyPart1 = new MimeBodyPart();
BodyPart bodyPart2 = new MimeBodyPart();
// 以multipart方式发送邮件内容
bodyPart1.setText(text);
// 发送邮件附件
// 放置文件File
for (int i = 0; i < pathList.size(); i++) {
// 添加附件路径
DataSource dataSource = new FileDataSource(pathList.get(i));
bodyPart2.setDataHandler(new DataHandler(dataSource));
// 添加附件名称
bodyPart2.setFileName(pathNameList.get(i));
}
// 添加到邮件容器中
multipart.addBodyPart(bodyPart1);
multipart.addBodyPart(bodyPart2);
// 将该类型邮件容器放入message中
message.setContent(multipart);
return message;
}
在添加完附件之后,你会发现一个设置邮件类型的方法:
// 设置邮件支持多种格式的发送与接收
public static void sendAndCollect() {
MailcapCommandMap mc = (MailcapCommandMap) CommandMap
.getDefaultCommandMap();
mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
mc.addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
CommandMap.setDefaultCommandMap(mc);
}
这就是我们需要的所有邮件主体类型。
完成以上代码片段就可以完成邮件的发送了。当然,SMTPS和以上差不了多少。在加密SSL or TLS都可以,一下是三者的对比:
普通邮件:
Properties props = new Properties();// key=value
props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.host",smtp);
props.setProperty("mail.smtp.auth", "true");
SSL加密发送:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
Properties props = System.getProperties();
// 端口
int port = 465;
props.setProperty("mail.smtp.host", smtp);
props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY);
props.setProperty("mail.smtp.socketFactory.fallback", "false");
props.setProperty("mail.smtp.port", String.valueOf(port));
props.setProperty("mail.transport.protocol", "smtp");
props.setProperty("mail.smtp.socketFactory.port",
String.valueOf(port));
props.put("mail.smtp.auth", "true");
TLS发送:
Properties props = System.getProperties();
// 端口
int port = 587;
props.put("mail.smtp.auth", "true");
// TODO TEST
props.put("mail.smtp.host", smtp);
props.put("mail.smtp.port", ""+port);
props.put("mail.smtp.starttls.enable", "true");
如果你完成了以上的所有代码就可以发送自己写好的数据并发送到制定邮箱中,可能他看起来和平常工作中的不太一样(没有邮件签名,没有彩色分割线等待)。因为这是后面需要了解的HTML类型的邮件。
2.发送HTML邮件
在发送HTML邮件时要知道MIME邮箱协议:
像图中一样,邮件会通过Multipart类型来对要封装的邮件进行层层包裹,HTML,TEXT,IMAGE,附件等等。都会嵌入到其中。
multipart/mixed
混合组合类型:内容多种多样,类型可以随意组合
multipart/related
依赖组合类型:比如说我们需要在纯文本数据中插入图片时(不是附件),需要通过标签来进行图片内嵌。此时嵌入到HTML后数据为超文本数据。
multipart/alternative
选择组合类型:内部存有纯文本+超文本格式的邮件,他们会成为该类型。使其提高对不同客户端的兼容。
可以看出最复杂的邮箱就是三者相加了。于是在我们解析邮件体时时最为麻烦的,需要分不同类型来不同解析,而又因为多层嵌套的原因我们需要方法迭代。
而发送方则不需要关心太多,只需要知道在合适的收好设置好你的HTML就行了。我在后面也是对HTML进行数据处理,而一般情况手机很少发送图片,当然也可以自己设置。
发送HTML邮件:
// 发送HTML邮件
public static Message sendHTMLMessage(Message message, String text,
List pathList, List pathNameList, boolean flag,
String type) throws MessagingException, IOException {
Multipart multipart = new MimeMultipart();
BodyPart bodyPart1 = new MimeBodyPart();
String content = Helps.head + text + Helps.tail;
bodyPart1.setContent(content , "text/plain;charset=gb2312");
multipart.addBodyPart(bodyPart1);
// 发送邮件附件
if (flag) {
// 放置文件File
BodyPart bodyPart = new MimeBodyPart();
for (int i = 0; i < pathList.size(); i++) {
// 添加附件路径
DataSource dataSource = new FileDataSource(pathList.get(i));
bodyPart.setDataHandler(new DataHandler(dataSource));
// 添加附件名称
bodyPart.setFileName(pathNameList.get(i));
}
multipart.addBodyPart(bodyPart);
}
// 将该类型邮件容器放入message中
message.setContent(multipart);
return message;
}
此时需要注意的是HTML文本格式,GB2312类型,否则中文会变成????到接收方。
Helps.head和Helps.tail是超文本数据的前部分和后部分。可以参考HTML格式来编写。
而需要在文本中内嵌图片则需要设置Content-ID和img标签。
String htmlText = "Hello
" +
"
";
messageBodyPart.setContent(htmlText, "text/html");
// 创建一个依赖组合类型
MimeMultipart multipart = new MimeMultipart("related");
multipart.addBodyPart(messageBodyPart);
// 创建第二层MIME
messageBodyPart = new MimeBodyPart();
// 添加图片文件地址
DataSource fds = new FileDataSource(file);
messageBodyPart.setDataHandler(new DataHandler(fds));
// 设置好Content-ID名字,一定要与在img标签中设置的cid:相同
messageBodyPart.setHeader("Content-ID","memememe");
// 添加到容器中
multipart.addBodyPart(messageBodyPart);
// 放置到邮件中
message.setContent(multipart);
如上看到的,如果打开MIME邮件体中可以看到,在HTML文件中的img标签cid引用的是一个类似地址的引用。
此时就可以根据上面所示来添加不同的数据到邮件中并发送。