java发送exchange邮件问题

最近工作中遇到一个问题,本来很简单的一个问题,困扰了我2周

具体:java发送会议邮件到exchange服务器

奇怪:系统有80多家客户,基本大半都有会议邮件的发送,不管是outlook,网易闪电邮,Foxmail另外wps邮箱都可以接收到会以邮件

只有exchange不能接收到会议邮件,收到的只是

BEGIN:VCALENDAR
PRODID:-//Events Calendar//iCal4j 1.0//EN CALSCALE:GREGORIAN
VERSION:2.0
METHOD:REQUEST
BEGIN:VEVENT
DTSTAMP:20160805T115502Z
DTSTART:20160808T160000
DTEND:20160808T223000
SUMMARY:test
LOCATION:test
UID:3f3acf56-0b54-4963-bba2-f02d2c222a8c
ORGANIZER:1
SEQUENCE:0
ATTENDEE;ROLE=OPT-PARTICIPANT;CN=Developer1:mailto:[email protected]

BEGIN:VALARM
TRIGGER:-PT10M
REPEAT:1
DURATION:PT10M
SUMMARY:Event Alarm
ACTION:DISPLAY
DESCRIPTION:Progress Meeting at 9:30am
END:VALARM
END:VEVENT
END:VCALENDAR

并且邮件中的正文,已附件的形式存在,并且看了网上很多类似的解决方式,综合起来的代码

/**
     * 发送邀请
     * @param cycleModel
     */
    protected void sendEmail(CycleMailModel cycleModel) {

        Properties properties = new Properties();
        properties.put("mail.transport.protocol", "smtp");
        properties.put("mail.smtp.user", "smtp.XXX.com");
        properties.put("mail.smtp.host", cycleModel.getEmailHost());
        properties.put("mail.smtp.port", "25");
        properties.put("mail.smtp.auth", "true");

        final String username = cycleModel.getEmailAddress();
        final String password = cycleModel.getEmailPass();
        Authenticator authenticator = new Authenticator() {
            protected PasswordAuthentication getPasswordAuthentication() {
                return new PasswordAuthentication(username, password);
            }
        };

        Transport transport = null;

        try {
            Session session = Session.getDefaultInstance(properties,
                    authenticator);
            MimeMessage mimeMessage = new MimeMessage(session);
            mimeMessage.setSubject(cycleModel.getSubject());
            if(null != attendee && attendee.size() > 0){
                for (int i = 0; i < attendee.size(); i++) {
                    JSONObject mail = attendee.getJSONObject(i);
                    if(mail.containsKey("address")){
                        mimeMessage.addRecipient(javax.mail.Message.RecipientType.TO,
                                new InternetAddress(mail.getString("address")));
                    }
                }
            }
            mimeMessage.setFrom(new InternetAddress(username));
//method=REQUEST;

            mimeMessage.setSentDate(new Date());
            mimeMessage.setContent(getContentText(cycleModel));
            /*if(cycleModel.getMethodType() == 1){
            }else{
                mimeMessage.setContent(cancelVEvent(cycleModel));
            }*/

            mimeMessage.saveChanges();
            transport = session.getTransport("smtp");
            transport.connect("mail.sfsctech.com",username, password);
            transport.sendMessage(mimeMessage, mimeMessage.getAllRecipients());
        } catch (MessagingException e) {
            // TODO Auto-generated catch block
            JSONObject exception = JSONObject.fromObject(e);
            //异常邮箱
            if(exception.containsKey("invalidAddresses")){
                JSONArray invalidAddresses = exception.getJSONArray("invalidAddresses");
                if(null != invalidAddresses && invalidAddresses.size() > 0){
                    for (int i = 0; i < invalidAddresses.size(); i++) {
                        //修改发送失败状态
                        JSONObject mailObject = invalidAddresses.getJSONObject(i);
                        this.dao.updateInvalidAddressesState(cycleModel.getPrimaryKey(), mailObject.getString("address"),2,2);
                    }
                    logger.error("异常邮箱:"+invalidAddresses.toString());
                }
            }
            //被退回邮箱
            if(exception.containsKey("validUnsentAddresses")){
                JSONArray validUnsentAddresses = exception.getJSONArray("validUnsentAddresses");
                if(validUnsentAddresses.size() > 0){
                    this.attendee=validUnsentAddresses;
                    sendEmail(cycleModel);
                    System.out.println("会议邮件  发送失败,再次发送");
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (transport != null)
                try {
                    transport.close();
                } catch (MessagingException logOrIgnore) {
                }
        }
    }

/**
     * 邀请内容
     * @param cycleModel
     * @return
     * @throws Exception
     */
    protected Multipart getContentText(CycleMailModel cycleModel) throws Exception {
        // 时区
        /*
         * TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance()
         * .createRegistry(); TimeZone timezone =
         * registry.getTimeZone("Asia/Shanghai"); // 会议地点 // 会议时间
         * java.util.Calendar cal = java.util.Calendar.getInstance();
         *
         * cal.setTimeZone(timezone); cal.set(2015, 6, 2, 14, 0); // 月份是要早一个月
         * DateTime start = new DateTime(cal.getTime()); cal.set(2015, 6, 2, 14,
         * 30); DateTime end = new DateTime(cal.getTime());
         */
        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);

        DateTime start = new DateTime(format.parse(cycleModel.getBeginTime().substring(0, 16)).getTime());
        DateTime end = new DateTime(format.parse(cycleModel.getEndTime().substring(0, 16)).getTime());
        VEvent vevent = new VEvent(start, end, cycleModel.getSubject());
        vevent.getProperties().add(new Location(cycleModel.getLocation()));// 会议地点
        vevent.getProperties().add(new Uid(cycleModel.getEventUid()));

        Organizer org = new Organizer(URI.create("mailto:" + cycleModel.getEmailAddress()));
        vevent.getProperties().add(org);
        //主键
        Sequence sequence = new Sequence(cycleModel.getSequenceId());
        vevent.getProperties().add(sequence);

        if(cycleModel.getEventType() == 2){
            String endTime = cycleModel.getBeginTime().substring(0, 10) + " " + cycleModel.getEndTime().substring(11, 16);
            vevent.getEndDate().setDate(new DateTime(format.parse(endTime)));
            //添加事件规则 天、周
            vevent.getProperties().add(getRRule(cycleModel));
        }

        // 与会人
        int i = 1;
        for (int j = 0; j < this.attendee.size(); j++) {
            JSONObject emailObject = this.attendee.getJSONObject(j);
            if(emailObject.containsKey("address")){
                Attendee attendee = new Attendee(URI.create("mailto:" + emailObject.getString("address")));
                attendee.getParameters().add(Role.OPT_PARTICIPANT);
                attendee.getParameters().add(new Cn("Developer" + i));
                vevent.getProperties().add(attendee);
                i++;
            }
        }

        // --------VEvent Over----------
        // --------VAlarm Start----------
        // 提醒,提前10分钟
        VAlarm valarm = new VAlarm(new Dur(0, 0, -10, 0));
        valarm.getProperties().add(new Repeat(1));
        valarm.getProperties().add(new Duration(new Dur(0, 0, 10, 0)));
        // 提醒窗口显示的文字信息
        valarm.getProperties().add(new Summary("Event Alarm"));
        valarm.getProperties().add(Action.DISPLAY);
        valarm.getProperties().add(
                new Description("Progress Meeting at 9:30am"));

        // --------VAlarm Over-------------
        // --------日历对象 Start---------------
        Calendar icsCalendar = new Calendar();
        icsCalendar.getProperties().add(
                new ProdId("-//Events Calendar//iCal4j 1.0//EN"));
        icsCalendar.getProperties().add(CalScale.GREGORIAN);
        icsCalendar.getProperties().add(Version.VERSION_2_0);
        String method = "REQUEST";
        //新增或者编辑
        if(cycleModel.getMethodType().equals(1)){
            vevent.getAlarms().add(valarm);// 将VAlarm加入VEvent
            icsCalendar.getProperties().add(Method.REQUEST);
        }else{
            icsCalendar.getProperties().add(Method.CANCEL);
            method = "CANCEL";
        }

        icsCalendar.getComponents().add(vevent);// 将VEvent加入Calendar

        icsCalendar.validate();

        // 将日历对象转换为二进制流
        CalendarOutputter co = new CalendarOutputter(false);
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        co.output(icsCalendar, os);
        byte[] mailbytes = os.toByteArray();
        // --------日历对象 Over------------------
        BodyPart mbp = new MimeBodyPart();
        mbp.setContent(mailbytes, "text/calendar;method="+method+";charset=UTF-8");
        System.out.println("会议邮件  method = "+method);

        BodyPart content = new MimeBodyPart();
        content.setContent(cycleModel.getBody(), "text/html;charset=UTF-8");
        System.out.println("会议邮件  Body = "+cycleModel.getBody());

        MailcapCommandMap mc = (MailcapCommandMap) CommandMap
                .getDefaultCommandMap();
        mc
                .addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
        mc
                .addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
        mc
                .addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
        mc
                .addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
        mc
                .addMailcap("message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822");
        CommandMap.setDefaultCommandMap(mc);

        MimeMultipart mm = new MimeMultipart();
        mm.setSubType("related");
        mm.addBodyPart(mbp);
        mm.addBodyPart(content);
        return mm;
    }

BodyPart对象不管怎么转码都不能解决问题,并且exchange的服务器设置也没有什么特殊的地方,也没有过滤什么东西,这是为什么呢?

网上找了两种方法:用ical4j和不用

我这里用的就是ical4j,但是不行,不知道其他人是怎么做的

然后我就尝试不用ical4j

protected void sendEmail2(CycleMailModel cycleModel) {

        try {
            Properties props = new Properties();
            try {
                props.put("mail.smtp.port", "25");
//                props.put("mail.smtp.host", "smtp.xxx.com");
                props.put("mail.smtp.host", cycleModel.getEmailHost());
                props.put("mail.transport.protocol", "smtp");
                props.put("mail.smtp.auth", "true");
                props.put("mail.smtp.starttls.enable", "true");
                props.put("mail.smtp.ssl", "true");  

            } catch (Exception e) {
                e.printStackTrace();
            }  

            String fromEmail = cycleModel.getEmailAddress();
            String toEmail = this.attendee.getJSONObject(0).getString("address");
            Session session;  

            final String username = cycleModel.getEmailAddress();
            final String password = cycleModel.getEmailPass();
            class EmailAuthenticator extends Authenticator {
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(username, password);
                }
            }

            Authenticator authenticator = new EmailAuthenticator();
            session = Session.getInstance(props, authenticator);
            MimeMessage message = new MimeMessage(session);
            message.setFrom(new InternetAddress(fromEmail));
            message.addRecipient(Message.RecipientType.TO, new InternetAddress(toEmail));
            message.setSubject(cycleModel.getSubject());
            StringBuffer buffer = new StringBuffer();
            DateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
            DateFormat format2 = new SimpleDateFormat("yyyyMMdd:HHmmss");
            String beginTime = format2.format(format1.parse(cycleModel.getBeginTime()));
            beginTime = beginTime.replace(":", "T");
            String endTime = format2.format(format1.parse(cycleModel.getEndTime()));
            endTime = endTime.replace(":", "T");
            buffer.append("BEGIN:VCALENDAR\n"
                    + "PRODID:-//Microsoft Corporation//Outlook 9.0 MIMEDIR//EN\n"
                    + "VERSION:2.0\n"
                    + "METHOD:REQUEST\n"
                    + "BEGIN:VEVENT\n"
                    + "ATTENDEE;ROLE=REQ-PARTICIPANT;RSVP=TRUE:MAILTO:"+toEmail+"\n"
                    + "ORGANIZER:MAILTO:"+toEmail+"\n"
                    + "DTSTART:"
                    + beginTime+"\n"
                    + "DTEND:"
                    + endTime+"\n"
//                    + "LOCATION:该邮件只是为了在中outlook日历中您请假、外出的情况,无需回复或接受!\n"
                    + "UID:"+UUID.randomUUID().toString()+"\n"//如果id相同的话,outlook会认为是同一个会议请求,所以使用uuid。
                    + "CATEGORIES:SuccessCentral Reminder\n"
                    + "DESCRIPTION:Remind\n\n"
                    + "SUMMARY:Test meeting request\n" + "PRIORITY:5\n"
                    + "CLASS:PUBLIC\n" + "BEGIN:VALARM\n"
                    + "TRIGGER:-PT15M\n" + "ACTION:DISPLAY\n"
                    + "DESCRIPTION:Reminder\n" + "END:VALARM\n"
                    + "END:VEVENT\n" + "END:VCALENDAR");
            BodyPart messageBodyPart = new MimeBodyPart();
            // 测试下来如果不这么转换的话,会以纯文本的形式发送过去,
            //如果没有method=REQUEST;charset=\"UTF-8\",outlook会议附件的形式存在,而不是直接打开就是一个会议请求
            messageBodyPart.setDataHandler(new DataHandler(new ByteArrayDataSource(buffer.toString(),
                    "text/calendar;method=REQUEST;charset=\"gb2312\"")));
            System.out.println("邮件:"+buffer.toString());
            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(messageBodyPart);
            message.setContent(multipart);
            Transport.send(message);
        } catch (MessagingException me) {
            // TODO Auto-generated catch block
            JSONObject exception = JSONObject.fromObject(me);
            //异常邮箱
            if(exception.containsKey("invalidAddresses")){
                JSONArray invalidAddresses = exception.getJSONArray("invalidAddresses");
                if(null != invalidAddresses && invalidAddresses.size() > 0){
                    for (int i = 0; i < invalidAddresses.size(); i++) {
                        //修改发送失败状态
                        JSONObject mailObject = invalidAddresses.getJSONObject(i);
                        this.dao.updateInvalidAddressesState(cycleModel.getPrimaryKey(), mailObject.getString("address"),2,2);
                    }
                    logger.error("异常邮箱:"+invalidAddresses.toString());
                }
            }
            //被退回邮箱
            if(exception.containsKey("validUnsentAddresses")){
                JSONArray validUnsentAddresses = exception.getJSONArray("validUnsentAddresses");
                if(validUnsentAddresses.size() > 0){
                    this.attendee=validUnsentAddresses;
                    sendEmail2(cycleModel);
                    System.out.println("会议邮件  发送失败,再次发送");
                }
            }
            me.printStackTrace();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

这样做了,竟然就可以接收到了,我很无语

仔细看代码,没有ical4j的日历对象,也没有把邮件的正文或者日历对象转成  text/html;charset=UTF-8

为什么就可以了呢,很不解,并且这样的写法,其他的邮件服务器也是可以用的

时间: 2024-08-08 20:36:22

java发送exchange邮件问题的相关文章

Java发送QQ邮件-附jar包下载链接

Java发送QQ邮件 jar包链接 链接:https://pan.baidu.com/s/1mt7LsPVIuMl5HLXEOppWkQ 提取码:x4jf 示例代码: package java2; import javax.mail.*; import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import java.util.Properties; /** * 测试发送邮件 */ p

Java发送QQ邮件

面试的时候被问到这个问题,别人问我用Java发过邮件没有,被问得一脸懵逼.然后就研究了一下,不是很难,按照网上的方法折腾了几天就搞出来了. 首先,使用QQ邮箱发送邮件之前需要在邮箱里面配置,开启pop3和smtp服务,其实这就是两个网络协议,一个是接受邮件的协议,一个是发送邮件的协议: POP3 是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议.它是因特网电子邮件的第一个离线协议标准,P

java 实现 email 邮件发送最简单优雅的方式(网易 163 为例)

如何使用IMAP服务? 首先介绍一些邮件发送的基础知识,如果你已经知道可以跳过. 直接到 Email 邮件发送实现的部分. IMAP是什么? IMAP,即Internet Message Access Protocol(互联网邮件访问协议),您可以通过这种协议从邮件服务器上获取邮件的信息.下载邮件等. IMAP与POP类似,都是一种邮件获取协议. IMAP和POP有什么区别? POP允许电子邮件客户端下载服务器上的邮件,但是您在电子邮件客户端的操作(如:移动邮件.标记已读等),这是不会反馈到服务

java通过SMTP发送QQ邮件(参考自龙果学院)

java通过SMTP发送QQ邮件编辑 个人邮箱开通SMTP服务(进入个人邮箱,点击设置–>账户):  点击了账户后,往下拉可以看到SMTP服务选项,默认情况下这个选项是不开启的.点击开启腾讯会进行身份验证,身份验证通过以后,会收到一个用于使用SMTP的16位口令,验证身份的过程中把收到的口令保存下来,因为后面要使用SMTP功能必须要用到这个口令.  具体实现代码:     public static void main(String args[]) {        // 邮件内容       

java发送内嵌图片邮件

前言: 博客系统中需要邮件服务的功能,以前写过类似的功能,不过功能太简单了,仅仅是发送文本内容,现在尝试一下发送内嵌图片邮件! 准备工作: 请参考:http://www.cnblogs.com/hujunzheng/p/4792831.html 整体效果: 发送端:网易邮箱:接收端:qq邮箱. 1.web前端 2.在网易邮箱“已发送”中可以看见通过java代码发送的邮件 3.同样在qq邮箱中也可以看到这样的效果 实现过程: 1.web前端(bootstrap布局) <form action=&quo

java 实现注册时发送激活邮件+激活

在很多网站注册的时候,为了验证用户信息的真实合法,往往需要验证用户所填邮件的准确性.形式为:用户注册时填写邮箱,注册完成后,网站会向用户所填邮箱发送一封激活邮件,用户点击激活邮件中的链接后,方可完成注册. 最近项目中也用到这个需求,做了个Demo与大家分享,大至思想如下: 数据库表结构 用户表t_user有五个字段分别为用户名.密码.邮箱地址.激活码.状态: | username | password | email |code | state | 核心代码: UserManager.java

Exchange 2013 PowerShell发送SMTP邮件

作为一个Exchange管理员,我们可能需要使用PowerShell脚本自动化的发送电子邮件.下面一起学习下如何使用PowerShell脚本在你的组织中发送SMTP电子邮件信息. 怎么做到这点呢? PowerShell V2以及后续版本都提供了核心命令可以通过SMTP发送电子邮件信息.使用下面的语法可以发送一份电子邮件信息: Send-MailMessage -To [email protected] ` -From [email protected] ` -Subject "Test E-ma

java实现简单邮件发送

java实现简单邮件发送

exchange 2010 发送的邮件对方无法收到

大家好,有段时间没有发博客了,实在抱歉.多余的话不多说了,言归正传. 前2天有客户遇到个了棘手的问题,向我求助.下面我把此问题及处理方法分享给大家,希望对大家有所帮助 环境信息:exchange 2010 sp3(共2台服务器:1台CAS\HUB.1台MBX),没有高可用 问题描述:outlook客户端连接正常.OWA访问正常.接收邮件正常:发送邮件(包括:给自己发送.内网用户之间,内网用户向外部用户)显示发送成功,队列中没有排队,发件人没有收到退信,  但是收件人未收到邮件 处理过程: 通过问