Android后台发送邮件进行日志反馈

概要

最近在和解决用户反馈的问题,但是出现了不方便的事情.就是获取用户操作日志的问题.想来想去还是用比较隐晦的方法---发送邮件.(需要告知用户,不然会当成流氓的!)

发送邮件分为两种:

  1. 调用系统的发邮件功能发送邮件
  2. 使用特定的邮箱密码发送邮件

第一种需要用户登陆邮箱,有的用户可能还没有邮箱,不是很方便.所以采用第二种方法:

在APP内部埋好邮箱,密码给特定的邮箱发送邮件附件添加日志.

发送说明

发送基础

这里要使用JavaMail的三个jar包:

  1. activation.jar
  2. additionnal.jar
  3. mail.jar

发送流程

  1. 设置发送服务器
  2. 设置发送账户和密码
  3. 设置发送显示的名称,主题,内容和附件
  4. 设置接收者地址
  5. 发送邮件给接收者

发送实现

权限

发送带有附件的邮件,需要联网权限和读写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.不带附件的邮件:

Screenshot_1.png

2.带附件的邮件

Screenshot_2.png

完整的发送代码

为了方便使用,就写了个发送邮件的单例,代码如下:

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

The last modification time is:May 29th, 2017 at 03:34 pm
If you think my article is useful to you, please feel free to appreciate

11 条评论

  1. 小明

    您好,请问附件需要放在哪个位置?

    1. DevWiki
      @小明

      http://www.cnblogs.com/yejg1212/archive/2013/06/01/3112702.html

    2. DevWiki
      @小明

      需要附带日志的话,放在MultiPart里面,详细可参见这篇文章.
      Java发送邮件(带附件) - yejg1212 - 博客园

  2. 繁小

    请问发送邮件之后如何能在APP端确认已经发送成功了呀?

    1. DevWiki
      @繁小

      这个好像没法直接判断,有时间我研究研究.

  3. han

    楼主,我发过去以后邮箱的中文都为????,然后我在createMessage()中textPart.setContent(content, "text/html");的下面加了一句textPart.setText(content,"UTF-8");,然后邮箱里的文字就正常了,特此来说一下,顺便问一下,楼主可以转载吗?

    1. DevWiki
      @han

      可以转载的,附带原文链接就行了.

  4. xastdm

    谢谢楼主分享 混淆文件忘记了加 -keep class com.sun.**{*;}

    1. DevWiki
      @xastdm

      是的,忘了说混淆说明了.谢谢

  5. xastdm

    同样的代码 同样的条件 只是打包后邮件怎么就收不到了呢 楼主有没有遇到

    1. DevWiki
      @xastdm

      你使用是163邮箱,并且开启了SMTP了吗

Leave a Comment