email会邀的发送和取消(java)

email会邀的发送、取消和时区的设置(java)

1. 项目背景

	企业内部各项目交流比较频繁,涉及的会议也比较多,业务方希望在企业平台中整合待办和会邀的功能,在写代码的时候,发现如果不设置时区,或者直接设置为“Asia/Shanghai”,也会出现时区问题。

2. 常见问题

	本文使用 ical4j和javamail发送会议邀请实现邮件发送提醒功能,会邀发送和取消本身还是很简单的,网络上也有各种文档和实现,但在很多文档中普遍出现一个问题,就是会邀时区的问题,如果不设置时区,经常会出现有的同事收到的会邀时间正常,有的同事出现早了 8个小时,和标准时间差8小时的情况(UTC)

3. 代码实现

  1. maven依赖
		<dependency>
            <groupId>org.mnode.ical4j</groupId>
            <artifactId>ical4j</artifactId>
            <version>2.0.2</version>
        </dependency
  1. 业务参数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;
}
  1. 发送和取消
@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) {

        // 创建MIME消息准备发送邮件
        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.RecipientType.TO 发送
           * Message.RecipientType.CC 抄送
           * Message.RecipientType.BCC 密送
           */ 
          //  message.addRecipients(Message.RecipientType.TO, new Address[]{new InternetAddress(toEmail),
    //                                new InternetAddress("aaa@126.com"),
    //                                new InternetAddress("bbb@126.com")});
            message.setSubject(meetingVo.getSubject());

            // 创建时间
            DateTime start = new DateTime(meetingVo.getStartTime());
            DateTime end = new DateTime(meetingVo.getEndTime());
            // 这里一定要注意,如果设置时间的utc 属性,发送的时间就会出现时间差
            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());
            // TimeZone timezone = registry.getTimeZone("UTC");
            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);

            // 提前15钟提醒
            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()));
            // 将VAlarm加入meeting
            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\"")));

			/** MimeMultipart 的构造方法默认 设置 subtype ="mixed"
			* multipart/mixed:附件。
			* multipart/related:内嵌资源。
			* multipart/alternative:纯文本与超文本共存
			*/
            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) {
        // 创建MIME消息准备发送邮件
        MimeMessage message = mailSender.createMimeMessage();
        try {

            if (debug) {
                meetingVo.setReciveAddr(debugReceiver);
            }
            // message.setFrom(new InternetAddress(reminderSender));
            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)
        }
    }
}
  1. 测试案例
	@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();
        }
    }
  1. 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

参考文档

  1. https://www.cnblogs.com/xidianlxf/p/11032982.html
  2. http://www.gnu.org/software/classpathx/javamail/javadoc/javax/mail/internet/MimeMessage.html
  3. https://blog.csdn.net/u013447988/article/details/84098778
  4. http://blog.itpub.net/15182208/viewspace-730172
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值