本文实现了在好友生日前自动发送提醒邮件的功能。


 android.util.Patterns自带的正则表达式实现邮箱验证。 Calender获取日历。 DatePickerDialog实现选择日期。 AlarmManager定时器实现系统后台提醒功能。 Java mail系统自动发送邮件,使用Java mail发送文件需要网络权限。邮件,生日用SharedPreference保存。所有代码如下。


github    https://github.com/tashaerxing/SendMail



* AlarmManager定时器 四步
* AlarmManager是Android中的一种系统级别的提醒服务,它会为我们在特定的时刻广播一个指定的Intent。
* 相对时间:SystemClock.elapsedRealtime();
* 绝对时间:System.currentTimeMillis();
* 1.实例化 AlarmManager。
* AlarmManager alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
* 2.确认意图。Intent intent = new Intent(this,SendEmailIntentService.class);
* 3.延迟意图,get方法。PendingIntent pi = PendingIntent.getService(this,0,intent,0);
* 4.设置周期。set方法。//定时器:四个参数(绝对时间,当前系统时间,每天INTERVAL_DAY,pendingIntent)
* alarmManager.setRepeating(AlarmManager.RTC,System.currentTimeMillis(),
* AlarmManager.INTERVAL_DAY,pi);






package com.example.sendemail;

import android.Manifest;
import android.app.DatePickerDialog;
import java.util.Calendar;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import android.util.Patterns;
import android.app.AlarmManager;


public class MainActivity extends AppCompatActivity implements
        View.OnClickListener{

    private EditText mail;
    private TextView date;

    private Button ack;
    private int preyear;//初始化的年月日
    private int premonth;
    private int preday;
    private int themeResId;//日历格式
    private SharedPreferences sharedPreferences;
    private SharedPreferences.Editor editor;
    private AlarmManager alarmManager;
    private RadioGroup radioGroup;
    private boolean send;//判断是否开启生日提醒
    private RadioButton yesSend;
    private RadioButton noSend;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        requestWindowFeature(Window.FEATURE_NO_TITLE);加了这句话后程序崩溃,未解决日历样式
        init();

        date.setOnClickListener(this);
        ack.setOnClickListener(this);
        radioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId){
                    case R.id.yesSend:
                        editor.putBoolean("send",true);
                        editor.apply();
                        //发送邮件需要获取网络权限
                        if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.
                                INTERNET)!= PackageManager.PERMISSION_GRANTED){
                            //如果没有权限,向用户申请权限
                            ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest
                                    .permission.INTERNET},1);
                        }else {
                            StartEmailService();
                        }
                        break;
                    case R.id.noSend:
                        editor.putBoolean("send",false);
                        editor.apply();
                        //如果开启生日提醒,在这里关闭生日提醒
                        CancelEmailService();
                        break;
                    default:break;
                }
            }
        });

    }
    private void init(){
        mail = (EditText)findViewById(R.id.mail);
        date = (TextView) findViewById(R.id.date);
        ack = (Button)findViewById(R.id.ack);
        radioGroup = (RadioGroup)findViewById(R.id.pickMail);
        yesSend = (RadioButton)findViewById(R.id.yesSend);
        noSend = (RadioButton)findViewById(R.id.noSend);
        //获取系统时间
        Calendar calendar = Calendar.getInstance();
        //从sheredPerference中获取数据,没有数据显示当前时间
        sharedPreferences = getSharedPreferences("data",0);
        editor = sharedPreferences.edit();
        //初始化日期和邮箱
        preyear = sharedPreferences.getInt("year",calendar.get(Calendar.YEAR));
        premonth = sharedPreferences.getInt("month",calendar.get(Calendar.MONTH)+1);
        preday = sharedPreferences.getInt("day",calendar.get(Calendar.DAY_OF_MONTH));
        String Email = sharedPreferences.getString("email",null);//邮箱值
        send = sharedPreferences.getBoolean("send",false);

        date.setText(preyear+"年"+premonth +"月"+ preday+"日");
        mail.setText(Email);
        if(send){
//            radioGroup.check(yesSend.getId());
            yesSend.setChecked(true);
        }else {
//            radioGroup.check(noSend.getId());
            noSend.setChecked(true);
        }

//        Log.d("send 的值",String.valueOf(send));
//      themeResId = DatePickerDialog.THEME_HOLO_LIGHT;

        themeResId = 3;
    }

    public void StartEmailService(){
        //如果选中生日邮箱提醒,开启周期性系统服务
        alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
        Intent intent = new Intent(MainActivity.this,SendEmailIntentService.class);
        PendingIntent pi = PendingIntent.getService(MainActivity.this,0,intent,0);
        //定时器:四个参数(绝对时间,当前系统时间,每天INTERVAL_DAY,pendingIntent)
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),
                AlarmManager.INTERVAL_DAY,pi);
    }
    public void CancelEmailService(){
        alarmManager = (AlarmManager)getSystemService(ALARM_SERVICE);
        Intent intent = new Intent(MainActivity.this,SendEmailIntentService.class);
        PendingIntent pi = PendingIntent.getService(MainActivity.this,0,intent,0);
        //定时器:四个参数(绝对时间,当前系统时间,每天INTERVAL_DAY,pendingIntent)
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),
                AlarmManager.INTERVAL_DAY,pi);
        if(pi!=null){
            alarmManager.cancel(pi);
        }

    }
    @Override
    public void onRequestPermissionsResult(int requestCode,  String[] permissions,  int[] grantResults) {
        switch (requestCode){
            case 1:
                if(grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    //如果有网络,可以发送邮件
                    StartEmailService();
                }else {
                    //没有网络
                    Toast.makeText(this,"邮箱提醒开启失败,请开启网络权限",Toast.LENGTH_LONG).show();
                    noSend.setChecked(true);
                }
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.date:
                new DatePickerDialog(MainActivity.this, themeResId,new DatePickerDialog.OnDateSetListener() {
                    @Override
                    public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
                        //日期改变后,用sheredperfreference保存
                        month++;
                        preyear = year;
                        premonth = month;
                        preday = dayOfMonth;
                        editor.putInt("year",year);
                        editor.putInt("month",month);
                        editor.putInt("day",dayOfMonth);
                        editor.apply();
                        date.setText(year+"年"+month +"月"+ dayOfMonth+"日");
                    }
                },preyear,premonth-1,preday).show();
            case R.id.ack://在这里判断邮箱是否正确

                //首先获取输入的邮箱
                String email = mail.getText().toString();
                if("".equals(email)){
                    //email == null这里==并没有起作用,==比较的是两个对象的地址,equals比较的是两个对象的内容
                    //如果邮箱为空
                    Toast.makeText(MainActivity.this,"请输入邮箱"+email,Toast.LENGTH_SHORT).show();
                }else {
                    //如果邮箱不为空,判断邮箱格式是否正确
                    if(!isEmail(email)){
                        //如果邮箱格式不正确
                        Toast.makeText(MainActivity.this,"请输入正确的邮箱地址",Toast.LENGTH_SHORT).show();
                    }else {
                        //将真确的邮箱保存
                        editor.putString("email",email);
                        editor.apply();
                        Toast.makeText((MainActivity.this),"邮箱地址正确",Toast.LENGTH_SHORT).show();
                    //邮箱地址正确,记录下邮箱,和生日,在生日前三天发送邮件提醒。

                    }
                }
            default:break;
        }
    }
    public  boolean isEmail(String email){
        //邮箱的正则表达式
        return Patterns.EMAIL_ADDRESS.matcher(email).matches();
    }
}



Intent不能实现后台自动发送邮件的功能,改为Java mail




* javamail 实现发送邮件,首先需要依赖 additional.jar mail.jar activation.jar 3 jar 包。 * Properties 属性文件以 key value 存储值 * Authenticator 访问受保护的服务器资源 * Session 客户端与服务器端的会话。 Session 对象需要知道用来处理邮件的 SMTP 服务器。 * MimeMessage 存储我们实际发送的电子邮件信息, * InternetAddress 源地址和目标地址 * Transport 发送信息



链接失败:



properties.setProperty("mail.smtp.starttls.enable","true");//错误530。要打开tls安全传输层协议(TLS)用于在两个通信应用程序之间提供保密性和数据完整性。






package com.example.sendemail;
import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Calendar;
import java.text.SimpleDateFormat;
import javax.mail.MessagingException;
/**
 * An {@link IntentService} subclass for handling asynchronous task requests in
 * a service on a separate handler thread.
 * <p>
 * TODO: Customize class - update intent actions, extra parameters and static
 * helper methods.
 */
public class SendEmailIntentService extends IntentService {
    // TODO: Rename actions, choose action names that describe tasks that this
    // IntentService can perform, e.g. ACTION_FETCH_NEW_ITEMS
    private static final String ACTION_FOO = "com.example.sendemail.action.FOO";
    private static final String ACTION_BAZ = "com.example.sendemail.action.BAZ";

    // TODO: Rename parameters
    private static final String EXTRA_PARAM1 = "com.example.sendemail.extra.PARAM1";
    private static final String EXTRA_PARAM2 = "com.example.sendemail.extra.PARAM2";

    public SendEmailIntentService() {
        super("SendEmailIntentService");
    }

    /**
     * Starts this service to perform action Foo with the given parameters. If
     * the service is already performing a task this action will be queued.
     *
     * @see IntentService
     */
    // TODO: Customize helper method
    public static void startActionFoo(Context context, String param1, String param2) {
        Intent intent = new Intent(context, SendEmailIntentService.class);
        intent.setAction(ACTION_FOO);
        intent.putExtra(EXTRA_PARAM1, param1);
        intent.putExtra(EXTRA_PARAM2, param2);
        context.startService(intent);
    }

    /**
     * Starts this service to perform action Baz with the given parameters. If
     * the service is already performing a task this action will be queued.
     *
     * @see IntentService
     */
    // TODO: Customize helper method
    public static void startActionBaz(Context context, String param1, String param2) {
        Intent intent = new Intent(context, SendEmailIntentService.class);
        intent.setAction(ACTION_BAZ);
        intent.putExtra(EXTRA_PARAM1, param1);
        intent.putExtra(EXTRA_PARAM2, param2);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_FOO.equals(action)) {
                final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                handleActionFoo(param1, param2);
            } else if (ACTION_BAZ.equals(action)) {
                final String param1 = intent.getStringExtra(EXTRA_PARAM1);
                final String param2 = intent.getStringExtra(EXTRA_PARAM2);
                handleActionBaz(param1, param2);
            }
        }
//        Log.d("SendEmailIntentService","在这里发送邮件");
        SharedPreferences preferences = getSharedPreferences("data",0);
        String email = preferences.getString("email",null);
        if(!"".equals(email) && email!=null) {
//            //如果邮箱不为空,发送提醒邮件

            //使用intent发送邮件,不能自动发送
//            Intent sendEmail = new Intent(Intent.ACTION_SENDTO);//纯文本,不用附件
//            sendEmail.setData(Uri.parse("mailto:"+email));//目标地址
//            sendEmail.putExtra(Intent.EXTRA_SUBJECT,"生日提醒");//设置标题
//            sendEmail.putExtra(Intent.EXTRA_TEXT,"又有人过生日啦,礼物买好了吗?");//内容
//            startActivity(sendEmail);
            try {
                //判断日期,在生日前三天发送邮件
                SimpleDateFormat format = new SimpleDateFormat("MM-dd");
                //内存中的生日
                Calendar calendar1 = Calendar.getInstance();
                int biryear = preferences.getInt("year",0);
                int birmonth = preferences.getInt("month",0)-1;
                int birday = preferences.getInt("day",0);
                calendar1.set(biryear,birmonth,birday);
                String date1 = format.format(calendar1.getTime());
//                Log.d("data1",date1);

                //当前日期的三天前
        Calendar calendar2 = Calendar.getInstance();
                calendar2.set(Calendar.DATE,calendar2.get(Calendar.DATE)-3);
                String date2 = format.format(calendar2.getTime());
//                Log.d("date2",date2);

                if(date1.equals(date2)){
                    new SendMail(email).send();   
                }
                //使用Javamail发送邮件,能自动发送
            }catch (MessagingException e){
                e.printStackTrace();
            }
        }else {
//            Toast.makeText(this,"请输入邮箱地址",Toast.LENGTH_SHORT);
            stopSelf();
        }
    }

    /**
     * Handle action Foo in the provided background thread with the provided
     * parameters.
     */
    private void handleActionFoo(String param1, String param2) {
        // TODO: Handle action Foo
        throw new UnsupportedOperationException("Not yet implemented");
    }

    /**
     * Handle action Baz in the provided background thread with the provided
     * parameters.
     */
    private void handleActionBaz(String param1, String param2) {
        // TODO: Handle action Baz
        throw new UnsupportedOperationException("Not yet implemented");
    }
}
package com.example.sendemail;

import java.util.Properties;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class SendMail {
    private String target;
    public SendMail(String target){
        //目标邮箱地址
        this.target = target;
    }
    public void send()throws AddressException,MessagingException {
        Properties properties = new Properties();
        //设置验证setProperty的参数只能是String,更安全
    properties.setProperty("mail.smtp.host","smtp.qq.com");
        properties.setProperty("mail.smtp.auth","true");
        properties.setProperty("mail.smtp.starttls.enable","true");//错误530
//        properties.setProperty("mail,smtp.port","465");
        //访问受保护的服务器资源
        MyAuthenticator authenticator = new MyAuthenticator("851059665","itochdvtspfmbcca");
        //Session 客户端与服务器端的会话.Session对象需要知道用来处理邮件的SMTP服务器。
    Session session = Session.getInstance(properties,authenticator);
//        session.setDebug(true);//代表启用debug模式,可以在控制台输出smtp协议应答的过程
        // Message对象将存储我们实际发送的电子邮件信息,
        // Message需要知道应当选择哪一个JavaMail session。
    MimeMessage message = new MimeMessage(session);
        //源地址和目标地址
    InternetAddress soureceAddress = new InternetAddress("851059665@qq.com");
        InternetAddress targetAddress = new InternetAddress(target);
        //设置要发送的邮件信息
        message.setFrom(soureceAddress);
        message.addRecipient(Message.RecipientType.TO,targetAddress);
        message.setSubject("生日提醒");
        message.setText("又有人过生日啦,礼物准备好了吗?");
        message.saveChanges();

        //设置发送协议
    Transport transport = session.getTransport("smtp");
        transport.connect("smtp.qq.com","851059665@qq.com","itochdvtspfmbcca");
        transport.sendMessage(message,message.getAllRecipients());
        transport.close();
    }
}
package com.example.sendemail;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;

/**
 * Created by lenovo on 2018/5/28.
 */

public class MyAuthenticator extends Authenticator {

    String userName = null;
    String password = null;
    public MyAuthenticator(String userName,String password){
        this.userName = userName;
        this.password = password;
    }
    public MyAuthenticator() {
        super();
    }

    @Override
    protected PasswordAuthentication getPasswordAuthentication() {
        return new PasswordAuthentication(userName,password);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.sendemail.MainActivity">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:gravity="center_vertical|left"
        android:textSize="18sp"
        android:text="请输入正确的邮箱地址" />
    <EditText
        android:id="@+id/mail"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:textSize="18sp"
        android:lines="1"
        android:inputType="textEmailAddress"
        android:gravity="center_vertical|left"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:textSize="18sp"
        android:gravity="center_vertical|left"
        android:text="请输入好友生日"/>

    <TextView
        android:id="@+id/date"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:gravity="center_vertical|left"
        android:clickable="true"
        android:textSize="18sp"
        />
    <Button
        android:id="@+id/ack"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="2"
        android:textSize="18sp"
        android:gravity="center"
        android:text="确定"/>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="0dp"
        android:orientation="horizontal"
        android:textSize="18sp"
        android:gravity="center_vertical|left"
        android:layout_weight="2">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:gravity="center_vertical|left"
            android:text="是否开启生日提醒"/>
        <RadioGroup
            android:id="@+id/pickMail"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <RadioButton
                android:id="@+id/yesSend"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:gravity="center_vertical|left"
                android:text="是"
                />
            <RadioButton
                android:id="@+id/noSend"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="18sp"
                android:gravity="center_vertical|left"
                android:text="否"
                android:checked="true"
                />
        </RadioGroup>

    </LinearLayout>

</LinearLayout>