摘要: JavaMail发送基本邮件ATA上有的是,但这次有个需求提出要实现会议邮件,呃,习惯性看有没有同学已经实现了,居然少之又少,不知道是不是有其他团队有这种需求,目测也不多哈哈,实现了这个功能感觉还挺有意思的,分享给大家交流交流。(可能有些理解不对,请大家指出,谢谢) 前期真的是比较懵圈,虽然一开始已经有实现了普通邮件发送,是通过Spring提供的 MimeMessageHelper 这个组件
JavaMail发送基本邮件ATA上有的是,但这次有个需求提出要实现会议邮件,呃,习惯性看有没有同学已经实现了,居然少之又少,不知道是不是有其他团队有这种需求,目测也不多哈哈,实现了这个功能感觉还挺有意思的,分享给大家交流交流。(可能有些理解不对,请大家指出,谢谢)
前期真的是比较懵圈,虽然一开始已经有实现了普通邮件发送,是通过Spring提供的MimeMessageHelper这个组件,说是摆脱繁杂的JavaMail API,封装了一些实现,简化了使用,但如果用这它去实现会议邮件,我试了很久都不行。呃,深入方法去看实现,呃,原来它的底层是MimeMessage,提供setText()也是。所以,我想如果要实现会议邮件,只能考虑抛弃helper这个组件去用JavaMail API重新实现。中间联系过阿里云邮的同学,他们告诉我没有提供HSF服务或通用API,只需要实现SMTP协议就可以了,行吧,开工。
实现效果图先晒为敬:
邮件内容效果图
日历效果图
下面讲下实现代码:
最关键是两点,一是实现RFC2445标准(日历数据交换),会议邮件的核心;二是理解JavaMail实现发送邮件的关联,下面关联图的左边部分就是了。没实现前觉得挺难,理解了就是拼装的事。
第一点我是利用ical4j实现的,maven(org.mnode.ical4j:ical4j:1.0.7)
邮件内容我是用velocity生成的String填充进去的,百度就有这里不做介绍,freemarker大家也可以试试。
邮件中还可以根据需要添加附件,addBodyPart实现就可以了。
[Java] 纯文本查看 复制代码
?
// 注入bean必备
private final static String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
@Autowired
private JavaMailSender mailSender;
@Resource
private VelocityEngine velocityEngine;
// 请根据你们自己的需要或申请配置
@Value("${spring.mail.username}")
private String fromMailAddress_preview;
@Value("${spring.mail.host}")
private String mailHost;
@Value("${spring.mail.username}")
private String mailUsername;
@Value("${spring.mail.password}")
private String mailPassword;
@Value("${spring.mail.port}")
private String mailPort;
@Value("${spring.mail.properties.mail.smtp.socketFactory.port}")
private String mailSmtpSocketFactoryPort;
@Value("${spring.mail.properties.mail.smtp.auth}")
private String mailSmtpAuth;
发送会议邮件模板方法:
[Java] 纯文本查看 复制代码
?
/**
*
*/
public Boolean sendMeetingMailTemplate(String[] toMailAddressArray, String mailSubject, String mailContent,
String summary, Long startTimestamp, Long endTimestamp, String locationContent) { if (toMailAddressArray == null || toMailAddressArray.length <= 0 || StringUtils.isEmpty(fromMailAddress_preview) || StringUtils.isEmpty(mailSubject) || StringUtils.isEmpty(mailContent) || StringUtils.isEmpty(summary)) { return false; } boolean sendStatus = false; Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); Properties prop = new Properties(); prop.put("mail.smtp.host", mailHost); prop.put("mail.smtp.auth", mailSmtpAuth); prop.put("mail.smtp.port", mailPort); prop.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY); prop.setProperty("mail.smtp.socketFactory.fallback", "false"); prop.setProperty("mail.smtp.socketFactory.port", mailSmtpSocketFactoryPort); MailAuthenticator authenticator = new MailAuthenticator(mailUsername, mailPassword); Session session = Session.getDefaultInstance(prop, authenticator); MimeMessage message = new MimeMessage(session); try { message.addHeaderLine("method=REQUEST"); message.addHeaderLine("charset=UTF-8"); message.addHeaderLine("component=VEVENT"); message.setFrom(new InternetAddress(fromMailAddress_preview)); InternetAddress[] addressArray = new InternetAddress[toMailAddressArray.length]; for (int i = 0; i < toMailAddressArray.length; i++) { addressArray[i] = new InternetAddress(toMailAddressArray[i]); } message.addRecipients(Message.RecipientType.TO, addressArray); message.setSubject(mailSubject); } catch (MessagingException e) { e.printStackTrace(); } // 会议内容核心拼装 BodyPart meetingBodyPart = new MimeBodyPart(); try { meetingBodyPart.setHeader("Content-Class", "urn:content- classes:calendarmessage"); meetingBodyPart.setHeader("Content-ID", "calendar_message"); meetingBodyPart.setDataHandler(new DataHandler(new ByteArrayDataSource( buildCalendar(summary, startTimestamp, endTimestamp, locationContent, toMailAddressArray).toString(), "text/calendar"))); } catch (IOException | MessagingException e) { e.printStackTrace(); } // 邮件原文组合+发送 Multipart multipart = new MimeMultipart(); try { multipart.addBodyPart(meetingBodyPart); BodyPart contentBodyPart = new MimeBodyPart(); // 普通文件赋值 //contentBodyPart.setText(mailContent); /* HTML内容赋值 Map<String, Object> model = new HashMap<>(); model.put("sscontent", "test测试师善"); VelocityContext velocityContext = new VelocityContext(); model.put("sscontent", model.get("sscontent")); String text = VelocityEngineUtils.mergeTemplateIntoString(velocityEngine, "/mail/test.vm", "UTF-8", model);*/ contentBodyPart.setContent(mailContent, "text/html; charset=utf-8"); multipart.addBodyPart(contentBodyPart); message.setContent(multipart); Transport.send(message); sendStatus = true; } catch (MessagingException e) { e.printStackTrace(); } return sendStatus;
}
构建日历对象方法:
[Java] 纯文本查看 复制代码
?
/**
*
*/
public Calendar buildCalendar(String summary, Long startTimestamp, Long endTimestamp, String LocationContent, String[] toMailAddressArray) {
TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry(); TimeZone timezone = registry.getTimeZone("Asia/Shanghai"); VTimeZone tz = timezone.getVTimeZone(); // 创建日历 Calendar calendar = new Calendar(); calendar.getProperties().add(new ProdId("-//Ben Fortuna//iCal4j 1.0//EN")); calendar.getProperties().add(Version.VERSION_2_0); calendar.getProperties().add(CalScale.GREGORIAN); // :star:️下面这行很关键,缺少的话钉钉IOS邮箱会显示1970--01-01 08:00 calendar.getProperties().add(Method.REQUEST); DateTime start = new DateTime(startTimestamp); start.setTimeZone(timezone); DateTime end = new DateTime(endTimestamp); end.setTimeZone(timezone); VEvent event = new VEvent(start, end, summary); event.getProperties().add(new Location(LocationContent)); try { // 生成唯一标示 event.getProperties().add(new Uid(new UidGenerator("iCal4j").generateUid().getValue())); // 添加时区信息 event.getProperties().add(tz.getTimeZoneId()); // 组织者 event.getProperties().add(new Organizer("mailto:preview@alibaba-inc.com")); } catch (SocketException | URISyntaxException e) { e.printStackTrace(); } // 添加邀请者 for (int i = 0; i < toMailAddressArray.length; i++) { Attendee dev = new Attendee(URI.create("mailto:" + toMailAddressArray[i])); dev.getParameters().add(Role.REQ_PARTICIPANT); dev.getParameters().add(new Cn("Developer " + (i + 1))); event.getProperties().add(dev); } /* // 重复事件 Recur recur = new Recur(Recur.WEEKLY, Integer.MAX_VALUE); recur.getDayList().add(WeekDay.MO); recur.getDayList().add(WeekDay.TU); recur.getDayList().add(WeekDay.WE); recur.getDayList().add(WeekDay.TH); recur.getDayList().add(WeekDay.FR); RRule rule = new RRule(recur); event.getProperties().add(rule); */ // 提醒,提前10分钟 VAlarm valarm = new VAlarm(new Dur(0, 0, -10, 0)); valarm.getProperties().add(new Summary("事件提醒")); valarm.getProperties().add(Action.DISPLAY); valarm.getProperties().add(new Description("会议提醒描述,待定,不确定使用方式")); // 将VAlarm加入VEvent event.getAlarms().add(valarm); // 添加事件 calendar.getComponents().add(event); // 验证 try { calendar.validate(); } catch (ValidationException e) { e.printStackTrace(); } return calendar;
}