Java发送邮件
Java发送邮件有两种发送方式
1、单独发送(不和任何框架整合)=》代码多,不容易记忆,使用时可以百度。
2、和Spring整合
发送邮件的支持包
1、javax-mail(过时了,但是可以使用)
2、sun公司的mail组件
本文案例依托于上一篇SSM整合环境搭建
activation-1.1.1
javax.mail-1.6.2spring-context-support-5.1.9.RELEASE
mail.host=smtp.qq.com mail.username=xxxxxx8@qq.com mail.password=kybtqndfzeslgidg mail.defaultEncoding=utf-8
<!-- 加载外部配置文件--> <context:property-placeholder location="classpath:mail.properties"/> <!-- 配置JavaMailSender 邮件--> <bean class="org.springframework.mail.javamail.JavaMailSenderImpl"> <property name="host" value="${mail.host}"/> <property name="username" value="${mail.username}"/> <property name="password" value="${mail.password}"/> <property name="defaultEncoding" value="${mail.defaultEncoding}"/> </bean>
@Controller public class MailController { @Autowired private JavaMailSender javaMailSender; @GetMapping("sendMail") @ResponseBody public String sendLoginCodeMail(String to, String code) { SimpleMailMessage simpleMailMessage = new SimpleMailMessage(); //邮件发送者 simpleMailMessage.setFrom("发件人昵称<xxxxxx@qq.com>"); //邮件接受者 simpleMailMessage.setTo(to); //邮件主题 simpleMailMessage.setSubject("验证码"); //邮件内容 simpleMailMessage.setText("你的登录验证码为 :" + code + "两分钟内有效"); //回复邮件 //simpleMailMessage.setReplyTo(); //表示抄送邮件 //simpleMailMessage.setCc(); //表示密送 //simpleMailMessage.setBcc(); //设置发送日期 //simpleMailMessage.setSentDate(); javaMailSender.send(simpleMailMessage); return "success"; } }
注意:此后的案例都是在发送简单邮件的基础上编写,重复部分不在复写,并且不在写注解、返回类型及返回值
/** * 发送带附件的邮件 * 复杂的邮件消息 */ public void sendMailWithFile(ToEmail toEmail) { // MimeMessage发送复杂邮件的消息本身 MimeMessage mimeMessage = javaMailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setFrom("Lolita<xxxxxx@qq.com>"); helper.setTo(toEmail.getTo()); helper.setSubject(toEmail.getSubject()); helper.setText(toEmail.getText()); //携带的附件 第一个参数表示附件的名称,第二个参数表示文件的位置 helper.addAttachment(toEmail.getSendLocalFile().get("fileName"), new File(toEmail.getSendLocalFile().get("filePath"))); javaMailSender.send(mimeMessage); System.out.println("发送成功"); } catch (MessagingException e) { e.printStackTrace(); } }
/** * 发送带附件的邮件 以文件上传的方是上传附件 */ public void sendMailByUpload(ToEmail toEmail) { System.out.println(toEmail); MimeMessage mimeMessage = javaMailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setFrom("Lolita<xxxxxx@qq.com>"); helper.setTo(toEmail.getTo()); helper.setSubject(toEmail.getSubject()); helper.setText(toEmail.getText()); InputStream inputStream = toEmail.getPart().getInputStream(); // byte[] buffer = new byte[1024]; //1K 128m 240 // int num=0; // List<Byte> list ; // StringBuffer buffer1 = new StringBuffer(); // ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(); // arrayInputStream.re // while ((num = inputStream.read())!=-1){ // // } // byte[] bytes = buffer1.toString().getBytes(); // byte[] buffer = new byte[inputStream.available()]; inputStream.read(buffer); helper.addAttachment(toEmail.getPart().getSubmittedFileName(),new ByteArrayResource(buffer)); javaMailSender.send(mimeMessage); System.out.println("上传成功"); } catch (MessagingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
/** * 发送内联资源邮件 */ public void sendMailInlineResource(ToEmail toEmail) { System.out.println(toEmail); MimeMessage mimeMessage = javaMailSender.createMimeMessage(); try { MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); helper.setFrom("Lolita<xxxxx@qq.com>"); helper.setTo(toEmail.getTo()); helper.setSubject(toEmail.getSubject()); //true 表示能识别HTML标签 helper.setText(toEmail.getText(),true); //添加内联资源 参数一 表示内容的ID可以随便写 参数二 表示指定你要发的内敛资源 helper.addInline("ftime",new File(toEmail.getSendLocalFile().get("filePath"))); javaMailSender.send(mimeMessage); System.out.println("上传成功"); } catch (MessagingException e) { e.printStackTrace(); } }
freemarker-2.3.23
在需要改动的地方使用${ }动态赋值
<html> <head></head> <body> <table border="0" cellspacing="0" cellpadding="0" style="padding-bottom:20px;max-width:516px;min-width:220px"> <tbody> <tr> <td width="8" style="width:8px"></td> <td> <div style="border-style:solid;border-width:thin;border-color:#dadce0;border-radius:8px;padding:40px 20px" align="center" class="m_8407418004312120846mdv2rw"> <img src="https://ci5.googleusercontent.com/proxy/T_zJ7UbaC9x27OP4-ZCPfDipqYLSGum30AlaxEycVclfvxO8Cze0sZ0kCrXlx6a-MgvW2tswbIyiNVfczjDuGh9okorzC5SUJDfwkHr6-3j1KUu94HuAw5uxM_jaElQef3Sub84=s0-d-e1-ft#https://www.gstatic.com/images/branding/googlelogo/2x/googlelogo_color_74x24dp.png" width="74" height="24" aria-hidden="true" style="margin-bottom:16px" alt="Google" class="CToWUd" /> <div style="font-family:‘Google Sans‘,Roboto,RobotoDraft,Helvetica,Arial,sans-serif;border-bottom:thin solid #dadce0;color:rgba(0,0,0,0.87);line-height:32px;padding-bottom:24px;text-align:center;word-break:break-word"> <div style="font-size:24px"> 尊敬的 ${adminName} 你好 : </div> <table align="center" style="margin-top:8px"> <tbody> <tr style="line-height:normal"> <td align="right" style="padding-right:8px"><img width="20" height="20" style="width:20px;height:20px;vertical-align:sub;border-radius:50%" src="https://lh4.googleusercontent.com/-Yw-z5rdKMhQ/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuckjcNzqy44Cp14ASh48P7xI2_JM0w/s96/photo.jpg" class="CToWUd" /></td> <td><a style="font-family:‘Google Sans‘,Roboto,RobotoDraft,Helvetica,Arial,sans-serif;color:rgba(0,0,0,0.87);font-size:14px;line-height:20px">${adminEmail}</a></td> </tr> </tbody> </table> </div> <div style="font-family:Roboto-Regular,Helvetica,Arial,sans-serif;font-size:14px;color:rgba(0,0,0,0.87);line-height:20px;padding-top:20px;text-align:center"> 您想用 Google 邮箱激活????图书账号。因此,我们向您发送这封电子邮件, <wbr />以确保该操作是您本人所为。你可以点击按钮进行激活。 <div style="padding-top:32px;text-align:center"> <a href="${activeUrl}"style="font-family:‘Google Sans‘,Roboto,RobotoDraft,Helvetica,Arial,sans-serif;line-height:16px;color:#ffffff;font-weight:400;text-decoration:none;font-size:14px;display:inline-block;padding:10px 24px;background-color:#4184f3;border-radius:5px;min-width:90px" target="_blank">点此激活</a> </div> </div> <div style="padding-top:20px;font-size:12px;line-height:16px;color:#5f6368;letter-spacing:0.3px;text-align:center"> 您也可以查看安全性活动 <br /> <a style="color:rgba(0,0,0,0.87);text-decoration:inherit">https://myaccount.google.com/<wbr />notifications</a> </div> </div> <div style="text-align:left"> <div style="font-family:Roboto-Regular,Helvetica,Arial,sans-serif;color:rgba(0,0,0,0.54);font-size:11px;line-height:18px;padding-top:12px;text-align:center"> <div> 我们向您发送这封电子邮件,目的是让您了解关于您的 Google 帐号和服务的重大变化。 </div> <div style="direction:ltr"> © 2020 Google LLC, <a class="m_8407418004312120846afal" style="font-family:Roboto-Regular,Helvetica,Arial,sans-serif;color:rgba(0,0,0,0.54);font-size:11px;line-height:18px;padding-top:12px;text-align:center">1600 Amphitheatre Parkway, Mountain View, CA 94043, USA</a> </div> </div> </div></td> <td width="8" style="width:8px"></td> </tr> </tbody> </table> </body> </html>
1、在springmvc配置模板文件的位置
<!-- 配置FreemarkerConfigure--> <bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/WEB-INF/template/"/> <property name="defaultEncoding" value="utf-8"/> </bean>2、读取模板并发送
@Controller public class FreemarkerController { /* * 配置模板的位置 * jsp也是一个模板引擎 * freemarker * * * */ @Autowired private FreeMarkerConfigurer freeMarkerConfigurer; @GetMapping("readTemplate") @ResponseBody public String readTemplate() throws Exception { Configuration configuration = freeMarkerConfigurer.getConfiguration(); //获取模板 Template template = configuration.getTemplate("active.ftl", "utf-8"); Map<String, String> map = new HashMap<>(); map.put("adminName", "xxxxxxx马宝国"); map.put("activeUrl", "http://www.baidu.com"); OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("E:\\active.html"), "utf8"); template.process(map, writer); writer.close(); return "success"; } }
实际工作中,会使用到很多的模板,不止一个,所以我们给读取模板抽出来,写一个方法获取模板的字符串数据
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
/** * 获取模板字符串 * @param templateName 模板名字 * @param data 模板中要添加的数据 * @return 模板的字符串 出异常(只会出获取模板异常)有返回空的字符串 */ public String getTemplateString(String templateName,Object data){ try { Template template = freeMarkerConfigurer.getConfiguration().getTemplate(templateName, "utf-8"); StringWriter stringWriter = new StringWriter(); //写入 template.process(data, stringWriter); //刷新 stringWriter.flush(); //生成字符串 String string = stringWriter.toString(); return string; } catch (IOException e) { e.printStackTrace(); } catch (TemplateException e) { e.printStackTrace(); } return ""; } /** * 发送模板邮件 * @param */ public void sendActiveEmail(String templateString,String email) { try { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "utf-8"); helper.setFrom("Lolita<1454711778@qq.com>"); helper.setTo(email); helper.setSubject("邮箱激活"); helper.setText(templateString, true); javaMailSender.send(mimeMessage); } catch (MessagingException e) { e.printStackTrace(); } }
因为发送邮件是一个耗时的操作,有可能会阻塞程序,所以我们把发送邮件这个操作放到子线程中操作
1、创建线程池
package top.ftime.wk.pool; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @author: JAVASM * @className: Asyncmanager * @description: * @date: 2021/6/8 15:50 * @version: 0.1 * @since: jdk1.8 * 单例模式设计线程池 */ public class AsyncManager { private static ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; private static AsyncManager asyncManager; private AsyncManager() { scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(50); } /** * 创建单例对象 * @return */ public static AsyncManager getInstance() { if (asyncManager == null) { return new AsyncManager(); } return asyncManager; } /** * 使用线程池执行内容 * 这种执行没有延迟时间 * * @param runnable */ public void execute(Runnable runnable) { scheduledThreadPoolExecutor.execute(runnable); } /** * 使用线程池执行内容 * 这种执行可以延迟一段时间后执行Runnable中的代码 * @param runnable * @param seconds 表示延迟的时间 */ public void schedule(Runnable runnable, long seconds) { scheduledThreadPoolExecutor.schedule(runnable, seconds, TimeUnit.SECONDS); } /** * 关闭线程池 */ public void release(){ scheduledThreadPoolExecutor.shutdownNow(); } }2、获取不在容器中的对象
package top.ftime.wk.utils; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; /** * @author: JAVASM * @className: StringUtils * @description: * @date: 2021/6/8 16:14 * @version: 0.1 * @since: jdk1.8 * 获取容器中的对象 */ @Component public class SpringUtils implements ApplicationContextAware{ /** * 获取容器中的对象 * 1、在容器中如何获取 * A在容器中,B也在容器中 * A想获取B 只需要在成员变量上添加@Autowired注解 * 2、不在容器中的类,如何获取容器中的对象 * ApplicationContext.getBean("") * 当项目启动时,这个方法就会走,会把系统的ApplicationContext传入这个函数中 * 前提是这个类要在容器中 */ private static ApplicationContext applicationContext1; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { applicationContext1 = applicationContext; } /** * 获得Bean * @param clazz * @param <T> * @return */ public static <T> T getBean(Class<T> clazz){ T bean = applicationContext1.getBean(clazz); return bean; } }
3、设计工厂发送邮件
package top.ftime.wk.factory; import com.alibaba.druid.support.spring.stat.SpringStatUtils; import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; import top.ftime.wk.utils.SpringUtils; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; /** * @author: JAVASM * @className: AsyncFactory * @description: * @date: 2021/6/8 16:07 * @version: 0.1 * @since: jdk1.8 * 工厂模式创建发送邮件的工厂 */ public class AsyncFactory { /** * 发送验证码邮件 * @param toUser * @param code * @return */ public static Runnable sendLoginCodeMail(String toUser,String code){ //获取容器中的对象 JavaMailSender bean = SpringUtils.getBean(JavaMailSender.class); SimpleMailMessage simpleMailMessage = new SimpleMailMessage(); //邮件发送者 simpleMailMessage.setFrom("Flower-time<1454711778@qq.com>"); //邮件接受者 simpleMailMessage.setTo(toUser); //邮件主题 simpleMailMessage.setSubject("验证码"); //邮件内容 simpleMailMessage.setText("你的登录验证码为 :" + code + "两分钟内有效"); Runnable runnable = ()->{ //当前线程名 System.out.println("当前线程为:"+Thread.currentThread().getName()); bean.send(simpleMailMessage); }; return runnable; } /** * 发送激活邮件 * @param templateString * @param toUser * @return */ public static Runnable sendActiveEmail(String templateString,String toUser){ try { JavaMailSender bean = SpringUtils.getBean(JavaMailSender.class); MimeMessage mimeMessage = bean.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, "utf-8"); helper.setFrom("Lolita<1454711778@qq.com>"); helper.setTo(toUser); helper.setSubject("邮箱激活"); helper.setText(templateString, true); Runnable runnable = ()->{ //当前线程名 System.out.println("当前线程为:"+Thread.currentThread().getName()); bean.send(mimeMessage); }; return runnable; } catch (MessagingException e) { e.printStackTrace(); } return ()->{}; } }4、使用
@Controller public class CommonController { @Autowired private AdminService adminService; private Jedis jedis = JedisUtil.getJedis(); /** * 登录验证 * 邮箱是否存在 * 用户是否激活 * 验证码邮件发送,保存在Redis中 * 耗时操作,放到子线程中操作 * * @param email * @return */ @GetMapping("getCode") @ResponseBody public AjaxResult loginGetCode(String email) { System.out.println("前端值" + email); //查询邮箱是否存在数据库 Admin adminByEmail = adminService.findAdminByEmail(email); System.out.println("查询值" + adminByEmail); if (null == adminByEmail) { //没有,返回邮箱不存在 System.out.println("不存在"); System.out.println(AjaxResult.error(AjaxStatus.EMAIL_NOT_FOUND)); return AjaxResult.error(AjaxStatus.EMAIL_NOT_FOUND); } else { //有,发送验证码 // 是否激活 if (adminByEmail.getActive()) { //激活,发送 String code = RandomCodeUtil.strCode(); //redis 缓存 jedis.set(email, code); //两分钟后自动删除 jedis.expire(email, 120); //邮件发送是一个耗时的操作 所以放到了子线程中,并使用工厂模式获取Runnable AsyncManager.getInstance().execute(AsyncFactory.sendLoginCodeMail(email,code)); return AjaxResult.success(); } else { //未激活,激活 return AjaxResult.error(AjaxStatus.ADMIN_NOT_ACTIVE); } } } }
原文:https://www.cnblogs.com/mini9264/p/14880371.html