email会邀的发送、取消和时区的设置(java)
1. 项目背景
企业内部各项目交流比较频繁,涉及的会议也比较多,业务方希望在企业平台中整合待办和会邀的功能,在写代码的时候,发现如果不设置时区,或者直接设置为“Asia/Shanghai”,也会出现时区问题。
2. 常见问题
本文使用 ical4j和javamail发送会议邀请实现邮件发送提醒功能,会邀发送和取消本身还是很简单的,网络上也有各种文档和实现,但在很多文档中普遍出现一个问题,就是会邀时区的问题,如果不设置时区,经常会出现有的同事收到的会邀时间正常,有的同事出现早了 8个小时,和标准时间差8小时的情况(UTC)
3. 代码实现
- maven依赖
<dependency>
<groupId>org.mnode.ical4j</groupId>
<artifactId>ical4j</artifactId>
<version>2.0.2</version>
</dependency
- 业务参数bean
@Data
@ApiModel(value = "会议邀请vo")
public class MeetingVo {
@ApiModelProperty(value = "会议内容")
String content;
@ApiModelProperty(value = "结束时间")
Date endTime;
@ApiModelProperty(value = "会议地点")
String location;
@ApiModelProperty(value = "接收人")
String reciveAddr;
@ApiModelProperty(value = "发件人")
String sendAddr;
@ApiModelProperty(value = "开始时间")
Date startTime;
@ApiModelProperty(value = "会议主题")
String subject;
@ApiModelProperty(value = "时区")
String timezone = "Asia/Shanghai";
@ApiModelProperty(value = "标示")
String uid;
}
- 发送和取消
@Service
@Slf4j
public class EmailAlertServiceImpl implements EmailAlertService {
@Value("${email.mailInTest}")
private boolean debug;
@Value("${email.testMailSendTo}")
private String debugReceiver;
@Autowired
private JavaMailSender mailSender;
@Override
public void sendMeeting(MeetingVo meetingVo) {
MimeMessage message = mailSender.createMimeMessage();
try {
if (debug) {
meetingVo.setReciveAddr(debugReceiver);
}
message.setFrom(new InternetAddress(meetingVo.getSendAddr()));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(meetingVo.getReciveAddr()));
message.setSubject(meetingVo.getSubject());
DateTime start = new DateTime(meetingVo.getStartTime());
DateTime end = new DateTime(meetingVo.getEndTime());
start.setUtc(true);
end.setUtc(true);
VEvent meeting = new VEvent(start, end, meetingVo.getSubject());
TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
TimeZone timezone = registry.getTimeZone(meetingVo.getTimezone());
VTimeZone tz = timezone.getVTimeZone();
meeting.getProperties().add(tz.getTimeZoneId());
meeting.getProperties().add(new Location(meetingVo.getLocation()));
Uid uid = new Uid(meetingVo.getUid());
meeting.getProperties().add(uid);
Organizer organizer = new Organizer(URI.create("mailto:" + meetingVo.getSendAddr()));
organizer.getParameters().add(new Cn("会邀提醒"));
meeting.getProperties().add(organizer);
Attendee attendee = new Attendee(URI.create("mailto:" + meetingVo.getReciveAddr()));
attendee.getParameters().add(Role.OPT_PARTICIPANT);
meeting.getProperties().add(attendee);
meeting.getProperties().add(new Summary(meetingVo.getSubject()));
ParameterList htmlParameters = new ParameterList();
XParameter fmtTypeParameter = new XParameter("FMTTYPE", "text/html");
htmlParameters.add(fmtTypeParameter);
XProperty htmlProp = new XProperty("X-ALT-DESC", htmlParameters, meetingVo.getContent());
meeting.getProperties().add(htmlProp);
VAlarm valarm = new VAlarm(new Dur(0, 0, -20, 0));
valarm.getProperties().add(new Summary("Event Alarm"));
valarm.getProperties().add(Action.DISPLAY);
valarm.getProperties().add(new Description(meetingVo.getSubject()));
meeting.getAlarms().add(valarm);
Calendar icsCalendar = new Calendar();
icsCalendar.getProperties().add(new ProdId("-//Events Calendar//iCal4j 1.0//EN"));
icsCalendar.getProperties().add(Version.VERSION_2_0);
icsCalendar.getProperties().add(Method.REQUEST);
icsCalendar.getComponents().add(meeting);
CalendarOutputter co = new CalendarOutputter(false);
Writer wtr = new StringWriter();
co.output(icsCalendar, wtr);
String mailContent = wtr.toString();
BodyPart messageBodyPart = new MimeBodyPart();
messageBodyPart.setDataHandler(new DataHandler(
new ByteArrayDataSource(mailContent, "text/calendar;method=REQUEST;charset=\"UTF-8\"")));
Multipart multipart = new MimeMultipart("alternative");
multipart.addBodyPart(messageBodyPart);
message.setContent(multipart);
mailSender.send(message);
} catch (Exception e) {
e.printStackTrace();
log.error("发送会邀出现异常:{}",e)
}
}
@Override
public void cancelMeeting(MeetingVo meetingVo) {
MimeMessage message = mailSender.createMimeMessage();
try {
if (debug) {
meetingVo.setReciveAddr(debugReceiver);
}
message.setFrom(new InternetAddress(meetingVo.getSendAddr()));
message.addRecipient(Message.RecipientType.TO, new InternetAddress(meetingVo.getReciveAddr()));
message.setSubject(meetingVo.getSubject());
message.setText("测试邮件--测试");
BodyPart messageBodyPart = new MimeBodyPart();
DateTime start = new DateTime(meetingVo.getStartTime());
DateTime end = new DateTime(meetingVo.getEndTime());
start.setUtc(true);
end.setUtc(true);
VEvent meeting = new VEvent(start, end, meetingVo.getSubject());
TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
TimeZone timezone = registry.getTimeZone(meetingVo.getTimezone());
VTimeZone tz = timezone.getVTimeZone();
meeting.getProperties().add(tz.getTimeZoneId());
meeting.getProperties().add(new Location(meetingVo.getLocation()));
meeting.getProperties().add(new Summary(meetingVo.getSubject()));
meeting.getProperties().add(new Description(meetingVo.getContent()));
Uid uid = new Uid(meetingVo.getUid());
meeting.getProperties().add(uid);
Organizer organizer = new Organizer(URI.create("mailto:" + meetingVo.getSendAddr()));
organizer.getParameters().add(new Cn("会邀取消"));
meeting.getProperties().add(organizer);
Attendee attendee = new Attendee(URI.create("mailto:" + meetingVo.getReciveAddr()));
attendee.getParameters().add(Role.OPT_PARTICIPANT);
meeting.getProperties().add(attendee);
Calendar icsCalendar = new Calendar();
icsCalendar.getProperties().add(new ProdId("-//Events Calendar//iCal4j 1.0//EN"));
icsCalendar.getProperties().add(Version.VERSION_2_0);
icsCalendar.getProperties().add(Method.CANCEL);
icsCalendar.getComponents().add(meeting);
CalendarOutputter co = new CalendarOutputter(false);
Writer wtr = new StringWriter();
co.output(icsCalendar, wtr);
String mailContent = wtr.toString();
messageBodyPart.setDataHandler(new DataHandler(
new ByteArrayDataSource(mailContent, "text/calendar;method=REQUEST;charset=\"UTF-8\"")));
Multipart multipart = new MimeMultipart();
multipart.addBodyPart(messageBodyPart);
message.setContent(multipart);
mailSender.send(message);
} catch (Exception e) {
e.printStackTrace();
log.error("取消会邀发生异常:{}",e)
}
}
}
- 测试案例
@Test
public void sendMeeting() {
MeetingVo meetingVo = new MeetingVo();
meetingVo.setSendAddr("test01@126.com");
meetingVo.setStartTime(new Date());
meetingVo.setEndTime(new Date());
meetingVo.setLocation("人民大会堂--百花厅");
meetingVo.setReciveAddr("test02@126.com");
meetingVo.setUid(UUID.randomUUID().toString());
meetingVo.setSubject("快来开会啦");
meetingVo.setContent("\xxx邀请您共商大计");
try {
emailAlertService.sendMeeting(meetingVo);
} catch (Exception e) {
e.printStackTrace();
}
}
- springboot配置
#meeting email
email.mailInTest=true
email.testMailSendTo=test01@126.com
####################### JavaMailSender Config ####################
spring.mail.host=xxxxx
spring.mail.username=
spring.mail.password=
spring.mail.properties.mail.smtp.auth=false
spring.mail.properties.mail.smtp.starttls.enable=false
spring.mail.properties.mail.smtp.starttls.required=false
参考文档
- https://www.cnblogs.com/xidianlxf/p/11032982.html
- http://www.gnu.org/software/classpathx/javamail/javadoc/javax/mail/internet/MimeMessage.html
- https://blog.csdn.net/u013447988/article/details/84098778
- http://blog.itpub.net/15182208/viewspace-730172