背景

甲方爸爸:新接入业务在国庆以及军运会期间需要每天巡检业务并发送邮件告知具体情况!

我司:没问题。

甲方爸爸:假期也要发噢。

我司:没问题(。。。)。

刚开始计划指定几个同事轮流发送,业务只要不被攻击一般是没有问题的。但是想一想休息日还要处理工作上的事情(非紧急的)就不爽,近几年一直在做前端的事情,后台碰的少,毕竟也接触过,所以决定搞一个定时发送邮件的程序,遂上网查找资料。

邮件类选择

在网上大致上看了下,目前有两种方案:

  1. MimeMessage
        String title = createTitle();
        String text = createText();
        Properties props = new Properties();
        props.put("mail.smtp.host", "smtp.qq.com");
        props.put("mail.transport.protocol", "smtp");
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.auth", "true");
        Session session = Session.getDefaultInstance(props, 
            new javax.mail.Authenticator() {
                protected PasswordAuthentication getPasswordAuthentication() {        
                 return new PasswordAuthentication(from, passwd);
                }
            });
        MimeMessage message = new MimeMessage(session);
        try {
            message.setFrom(new InternetAddress(from));
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));
            message.setSubject(title);
            message.setText(text);
            System.out.println(text);
            Transport.send(message);
        } catch(Exception e) {
            e.printStackTrace();
        }
  1. SimpleMail
        mail.setHostName(host);
        mail.setAuthentication(user, passwd);
        mail.setFrom(user);
        mail.setCharset("UTF-8");
        mail.setSubject(title);
        mail.setSSLOnConnect(true);
        mail.setMsg(content);
        mail.addTo(to);
        mail.send();

在本地重构代码并进行了测试,都是正常发送和接收,个人觉得SimpleMail看起来更加简洁,所以邮件类就选它了

定时器

网上搜索一大堆,具体就不一一介绍了,我用的是Quartz
Quartz 设计有三个核心类,分别是

  • Scheduler 调度器

调度器就相当于一个容器,装载着任务和触发器。该类是一个接口,代表一个 Quartz 的独立运行容器, TriggerJobDetail 可以注册到 Scheduler 中, 两者在 Scheduler 中拥有各自的组及名称, 组及名称是 Scheduler 查找定位容器中某一对象的依据, Trigger 的组及名称必须唯一, JobDetail 的组和名称也必须唯一(但可以和 Trigger 的组和名称相同,因为它们是不同类型的)。Scheduler 定义了多个接口方法, 允许外部通过组及名称访问和控制容器中 TriggerJobDetail

  • Job任务

定义需要执行的任务。该类是一个接口,只定义一个方法 execute(JobExecutionContext context),在实现类的 execute 方法中编写所需要定时执行的 Job(任务), JobExecutionContext 类提供了调度应用的一些信息。Job 运行时的信息保存在 JobDataMap 实例中

  • Trigger 触发器

负责设置调度策略。该类是一个接口,描述触发 job 执行的时间触发规则。主要有 SimpleTriggerCronTrigger 这两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger 是最适合的选择;而 CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案:如工作日周一到周五的 15:00~16:00 执行调度等

开发测试

发送者邮箱必须开启客户端POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务,具体可以在邮箱设置页进行设置,密码使用授权码
  1. 创建SendMail类,将发送邮件逻辑代码进行封装
public class SendMail implements Job {

    private static String user = "11111111@qq.com";
    private static String passwd = "passwd";//授权码
    private static String to = "22222@qq.com";
    private static String host = "smtp.qq.com";
    
    public static void sendMailForSmtp(String title, String content, String[] tos, String[] ccs) throws EmailException {
        SimpleEmail mail = new SimpleEmail();
        // 设置邮箱服务器信息
        mail.setHostName(host);
        // 设置密码验证器passwd为授权码
        mail.setAuthentication(user, passwd);
        // 设置邮件发送者
        mail.setFrom(user);
        // 设置邮件编码
        mail.setCharset("UTF-8");
        // 设置邮件主题
        mail.setSubject(title);
        //SSL方式
        mail.setSSLOnConnect(true);
        // 设置邮件内容
//        mail.setMsg(content);
        // 设置邮件接收者
//        mail.addTo(to);
        mail.addTo(tos);
        mail.addCc(ccs);
        // 发送邮件
        MimeMultipart multipart = new MimeMultipart();
        //邮件正文  
        BodyPart contentPart = new MimeBodyPart();  
        try {
            contentPart.setContent(content, "text/html;charset=utf-8");
            multipart.addBodyPart(contentPart);  
            //邮件附件  
            BodyPart attachmentPart = new MimeBodyPart();
            File file = new File("C:\\lutong\\20190918002.log");
            FileDataSource source = new FileDataSource(file);  
            attachmentPart.setDataHandler(new DataHandler(source));  
            attachmentPart.setFileName(MimeUtility.encodeWord(file.getName()));
            multipart.addBodyPart(attachmentPart);
            mail.setContent(multipart);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
        System.out.println(JsonUtil.toJson(mail));
        mail.send();
        System.out.println("mail send success!");
    }
    @Override
    public void execute(JobExecutionContext var1) throws JobExecutionException {
        // TODO Auto-generated method stub
        //多个接收者
        String[] tos = {"11111@qq.com","2222@qq.com"};
        //多个抄送者
        String[] ccs = {"33333@qq.com","44444@qq.com"};
        try {
            SendMail.sendMailForSmtp("title", "hello <br> ccy", tos, ccs);
        } catch (EmailException e) {
            e.printStackTrace();
        }
    }
}
  1. 创建CronTrigger,定时发送任务
public class CronTrigger {
    public static void main(String[] args){
        //初始化job
        JobDetail job = JobBuilder.newJob(SendMail.class)// 创建 jobDetail 实例,绑定 Job 实现类
                .withIdentity("ccy", "group1")//指明job名称、所在组名称
                .build();
        //定义规则
         Trigger trigger = TriggerBuilder
         .newTrigger()
         .withIdentity("ccy", "group1")//triggel名称、组
         .withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))//每隔5s执行
         .build();
        Scheduler scheduler = null;
        try {
            scheduler = new StdSchedulerFactory().getScheduler();
            System.out.println("start job...");
            //把作业和触发器注册到任务调度中
            scheduler.scheduleJob(job, trigger);
            //启动
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

测试结果

mail.png

后记

技术沟通群欢迎加入
weixinqun_1.png
如果对笔者感兴趣也欢迎你加我好友一起讨论技术,夸夸白
本人微信gm4118679254


桂马
36 声望5 粉丝

精心做事,大气为人