概要
最近在和解决用户反馈的问题,但是出现了不方便的事情.就是获取用户操作日志的问题.想来想去还是用比较隐晦的方法---发送邮件.(需要告知用户,不然会当成流氓的!)
发送邮件分为两种:
- 调用系统的发邮件功能发送邮件
- 使用特定的邮箱密码发送邮件
第一种需要用户登陆邮箱,有的用户可能还没有邮箱,不是很方便.所以采用第二种方法:
在APP内部埋好邮箱,密码给特定的邮箱发送邮件附件添加日志.
发送说明
发送基础
这里要使用JavaMail的三个jar包:
- activation.jar
- additionnal.jar
- mail.jar
发送流程
- 设置发送服务器
- 设置发送账户和密码
- 设置发送显示的名称,主题,内容和附件
- 设置接收者地址
- 发送邮件给接收者
发送实现
权限
发送带有附件的邮件,需要联网权限和读写SD卡权限,需要在Android Manifest.xml文件添加已下权限:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
设置发送信息
以下以163邮箱为例,需要提前在163邮箱设置里面开启smtp.
设置需要的常量
//发送账户
private static final String SENDER_NAME = "xxxxx@163.com";
//发送账户的密码
private static final String SENDER_PASS = "xxxxx";
//邮箱服务器
private static final String VALUE_MAIL_HOST = "smtp.163.com";
//邮箱服务器主机
private static final String KEY_MAIL_HOST = "mail.smtp.host";
//邮箱是否需要鉴权
private static final String KEY_MAIL_AUTH = "mail.smtp.auth";
//需要鉴权
private static final String VALUE_MAIL_AUTH = "true";
设置发送的属性
Properties properties = System.getProperties();
properties.put(KEY_MAIL_HOST, VALUE_MAIL_HOST);
properties.put(KEY_MAIL_AUTH, VALUE_MAIL_AUTH);
获取Session
Session session = Session.getInstance(properties, getAuthenticator());
private Authenticator getAuthenticator() {
return new Authenticator(){
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(SENDER_NAME, SENDER_PASS);
}
};
}
构建邮件消息
//创建消息
MimeMessage mimeMessage = new MimeMessage(session);
try {
//设置发送者
mimeMessage.setFrom(new InternetAddress(SENDER_NAME));
//设置接收者
InternetAddress[] addresses = new InternetAddress[]{new InternetAddress(SENDER_NAME)};
mimeMessage.setRecipients(Message.RecipientType.TO, addresses);
//设置邮件的主题
mimeMessage.setSubject(title);
//设置邮件的内容
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(content, "text/html");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(textPart);
mimeMessage.setContent(multipart);
//设置发送时间
mimeMessage.setSentDate(new Date());
} catch (MessagingException e) {
e.printStackTrace();
}
添加文件附件
private void appendFile(MimeMessage message, String filePath) {
try {
Multipart multipart = (Multipart) message.getContent();
MimeBodyPart filePart = new MimeBodyPart();
filePart.attachFile(filePath);
multipart.addBodyPart(filePart);
} catch (IOException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
添加多个文件附件
private void appendMultiFile(MimeMessage message, List<String> pathList) {
try {
Multipart multipart = (Multipart) message.getContent();
for (String path : pathList) {
MimeBodyPart filePart = new MimeBodyPart();
filePart.attachFile(path);
multipart.addBodyPart(filePart);
}
} catch (IOException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
发送邮件
Transport.send(mimeMessage);
发送结果
1.不带附件的邮件:
2.带附件的邮件
完整的发送代码
为了方便使用,就写了个发送邮件的单例,代码如下:
package net.devwiki.mailsender;
import android.os.AsyncTask;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.PasswordAuthentication;
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;
/**
* 邮件管理类
* Created by DevWiki on 2016/8/21.
*/
public class MailManager {
private static final String SENDER_NAME = "xxxxx@163.com";
private static final String SENDER_PASS = "xxxxx";
private static final String VALUE_MAIL_HOST = "smtp.163.com";
private static final String KEY_MAIL_HOST = "mail.smtp.host";
private static final String KEY_MAIL_AUTH = "mail.smtp.auth";
private static final String VALUE_MAIL_AUTH = "true";
public static MailManager getInstance() {
return InstanceHolder.instance;
}
private MailManager() {
}
private static class InstanceHolder {
private static MailManager instance = new MailManager();
}
class MailTask extends AsyncTask<Void, Void, Boolean> {
private MimeMessage mimeMessage;
public MailTask(MimeMessage mimeMessage) {
this.mimeMessage = mimeMessage;
}
@Override
protected Boolean doInBackground(Void... voids) {
try {
Transport.send(mimeMessage);
return Boolean.TRUE;
} catch (MessagingException e) {
e.printStackTrace();
return Boolean.FALSE;
}
}
}
public void sendMail(final String title, final String content) {
MimeMessage mimeMessage = createMessage(title, content);
MailTask mailTask = new MailTask(mimeMessage);
mailTask.execute();
}
public void sendMailWithFile(String title, String content, String filePath) {
MimeMessage mimeMessage = createMessage(title, content);
appendFile(mimeMessage, filePath);
MailTask mailTask = new MailTask(mimeMessage);
mailTask.execute();
}
public void sendMailWithMultiFile(String title, String content, List<String> pathList) {
MimeMessage mimeMessage = createMessage(title, content);
appendMultiFile(mimeMessage, pathList);
MailTask mailTask = new MailTask(mimeMessage);
mailTask.execute();
}
private Authenticator getAuthenticator() {
return new Authenticator(){
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(SENDER_NAME, SENDER_PASS);
}
};
}
private MimeMessage createMessage(String title, String content) {
Properties properties = System.getProperties();
properties.put(KEY_MAIL_HOST, VALUE_MAIL_HOST);
properties.put(KEY_MAIL_AUTH, VALUE_MAIL_AUTH);
Session session = Session.getInstance(properties, getAuthenticator());
MimeMessage mimeMessage = new MimeMessage(session);
try {
mimeMessage.setFrom(new InternetAddress(SENDER_NAME));
InternetAddress[] addresses = new InternetAddress[]{new InternetAddress(SENDER_NAME)};
mimeMessage.setRecipients(Message.RecipientType.TO, addresses);
mimeMessage.setSubject(title);
MimeBodyPart textPart = new MimeBodyPart();
textPart.setContent(content, "text/html");
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(textPart);
mimeMessage.setContent(multipart);
mimeMessage.setSentDate(new Date());
} catch (MessagingException e) {
e.printStackTrace();
}
return mimeMessage;
}
private void appendFile(MimeMessage message, String filePath) {
try {
Multipart multipart = (Multipart) message.getContent();
MimeBodyPart filePart = new MimeBodyPart();
filePart.attachFile(filePath);
multipart.addBodyPart(filePart);
} catch (IOException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
private void appendMultiFile(MimeMessage message, List<String> pathList) {
try {
Multipart multipart = (Multipart) message.getContent();
for (String path : pathList) {
MimeBodyPart filePart = new MimeBodyPart();
filePart.attachFile(path);
multipart.addBodyPart(filePart);
}
} catch (IOException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
后记
如果你需要完整的项目代码,请点击此处:MailSender
20 条评论
路过看一下!
android 8.0 带附件的邮件, 无法读取附件,读取权限已经开启。
部分异常栈是这样,怎么破, 大神?
05-15 10:34:07.144 29685-30662/com.kp2p.kp2ptools W/System.err: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: /storage/emulated/0/test.c (Permission denied)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:676)
at javax.mail.Transport.send0(Transport.java:189)
at javax.mail.Transport.send(Transport.java:118)
at com.kp2p.kp2ptools.KP2PMail$MailTask.doInBackground(KP2PMail.java:57)
at com.kp2p.kp2ptools.KP2PMail$MailTask.doInBackground(KP2PMail.java:46)
at android.os.AsyncTask$2.call(AsyncTask.java:345)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:257)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$W
是我这边自己的原因,没有动态申请存储权限。问题已经解决。
刚刚我测试了一下 。我这边只发送文本 是收的到的,但是我发送一个带有附件的文本 对方邮箱收不到 请问下这个问题怎么解决呢 而且我的文件是存在的 zip jpg都试过了
检测下存储权限的是否正常打开。是打发发
我下载下来写入文件路径 但是每次发送的时候只收到了文本 附件根本就没收到 怎么回事呢?
接收方在哪里设置?
已经找到了
en~
您好,请问附件需要放在哪个位置?
http://www.cnblogs.com/yejg1212/archive/2013/06/01/3112702.html
需要附带日志的话,放在MultiPart里面,详细可参见这篇文章.
[Java发送邮件(带附件) - yejg1212 - 博客园](http://www.cnblogs.com/yejg1212/archive/2013/06/01/3112702.html)
请问发送邮件之后如何能在APP端确认已经发送成功了呀?
这个好像没法直接判断,有时间我研究研究.
楼主,我发过去以后邮箱的中文都为????,然后我在createMessage()中textPart.setContent(content, "text/html");的下面加了一句textPart.setText(content,"UTF-8");,然后邮箱里的文字就正常了,特此来说一下,顺便问一下,楼主可以转载吗?
可以转载的,附带原文链接就行了.
谢谢楼主分享 混淆文件忘记了加 -keep class com.sun.**{*;}
是的,忘了说混淆说明了.谢谢
同样的代码 同样的条件 只是打包后邮件怎么就收不到了呢 楼主有没有遇到
你使用是163邮箱,并且开启了SMTP了吗