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

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

16 comments

  1. kobe

    刚刚我测试了一下 。我这边只发送文本 是收的到的,但是我发送一个带有附件的文本 对方邮箱收不到 请问下这个问题怎么解决呢 而且我的文件是存在的 zip jpg都试过了

  2. kobe

    我下载下来写入文件路径 但是每次发送的时候只收到了文本 附件根本就没收到 怎么回事呢?

  3. zhaoweihao

    接收方在哪里设置?

    1. zhaoweihao
      @zhaoweihao

      已经找到了

      1. DevWiki
  4. 小明

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

    1. DevWiki
      @小明

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

    2. DevWiki
      @小明

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

  5. 繁小

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

    1. DevWiki
      @繁小

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

  6. han

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

    1. DevWiki
      @han

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

  7. xastdm

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

    1. DevWiki
      @xastdm

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

  8. xastdm

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

    1. DevWiki
      @xastdm

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

Leave a Comment