zoukankan      html  css  js  c++  java
  • 用非Office库发送和编辑Meeting Request到Outlook

    本来想专心的做下WPF,最近这段时间在忙Product Demo,需要研究一下用C#代码去操作Outlook中的Meeting Request,上了一些国内外的论坛找到的东西,Demo过后就丢掉可惜了,但毕竟是花了时间的,总结分享一下,心理舒服些(很多知识来自stackoverflow,这里向大家推荐下)。这里主要总结功能的完整性和可用性。欢迎Office互操作经验多的同学补充。
    闲话结束,开始正题。

    在Outlook中,我们可以在Calendar里面发起一个meeting,并且可以对它修改或取消。通过Outlook的API,我们可以实现这些功能,但是很多情况下我们的服务器上并没有安装或者不允许安装Outlook,我们怎么不通过Outlook的API,用C#代码去实现这些功能?我们怎么以第三方的名义,向其他人发起一个Calendar Meeting Request?这个就是本文要讲解的情况。

    流程总的说来比较简单,就是有C#构建ICS文件,然后发送到mail server,当收件人收到的时候,Outlook会解析ICS文件,做相应的操作。

    1. 创建ICS格式文件。

    public string BuildIcsFormatString(DateTime startTime, DateTime endTime, ICollection<string> attendees, string organizer,
                string subject, string description, string guid, string location)
            {
                System.Text.StringBuilder sw = new System.Text.StringBuilder();
                sw.AppendLine("BEGIN:VCALENDAR");
                sw.AppendLine("VERSION:2.0");
                sw.AppendLine("METHOD:REQUEST");
                sw.AppendLine("BEGIN:VEVENT");
                if (attendees != null)
                {
                    foreach (string attendee in attendees)
                    {
                        sw.AppendLine("ATTENDEE;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:" + attendee);
                    }
                }
                sw.AppendLine("CLASS:PUBLIC");
                sw.AppendLine(string.Format("CREATED:{0:yyyyMMddTHHmmssZ}", DateTime.UtcNow));
                sw.AppendLine("DESCRIPTION:" + description);
                sw.AppendLine(string.Format("DTEND:{0:yyyyMMddTHHmmssZ}", endTime));
                sw.AppendLine(string.Format("DTSTAMP:{0:yyyyMMddTHHmmssZ}", DateTime.UtcNow));
                sw.AppendLine(string.Format("DTSTART:{0:yyyyMMddTHHmmssZ}", startTime));
                sw.AppendLine("ORGANIZER;CN=\"NAME\":mailto:" + organizer);
                sw.AppendLine("SEQUENCE:0");
                sw.AppendLine("UID:" + guid);
                sw.AppendLine("LOCATION:" + location);
                sw.AppendLine("SUMMARY;LANGUAGE=en-us:" + subject);
                sw.AppendLine("BEGIN:VALARM");
                sw.AppendLine("TRIGGER:-PT720M");
                sw.AppendLine("ACTION:DISPLAY");
                sw.AppendLine("DESCRIPTION:Reminder");
                sw.AppendLine("END:VALARM");
                sw.AppendLine("END:VEVENT");
                sw.AppendLine("END:VCALENDAR");
                return sw.ToString();
            }
    

    要点提示1-1: ICS文件中ROLE=REQ-PARTICIPANT指的是当前的attendee类型是Required的,如果我们需要某个attendee是Optional的,要用ROLE=OPT-PARTICIPANT。所以,这段代码还可以加强用于区分Required或Optional的attendee。

     要点提示1-2:我们如何通过ICS区分Create,Update?ICS是通过ID来区分不通的Calendar Meeting Request的,所以我们发出一个ICS文件,如果这个ID不在接受者的邮件系统中存在对应的Calendar Meeting Request,Outlook会执行Create操作;如果存在,Outlook会把该请求识别为一个Update操作。

     要点提示1-3:我们如何通过ICS执行Delete操作?根据1-2,我们首先需要一个已经存在的ID;还有ICS文件中METHOD:REQUEST应该被修改为METHOD:CANCEL(资料上说STATUS:CANCELLED也要添加在METHOD:CANCEL之后,但是经实际测试,没有发现差别)。

    2. 用SMTP发送

                            string meetingInfo = BuildIcsFormatString(...);
                        System.Net.Mime.ContentType mimeType = new System.Net.Mime.ContentType("text/calendar; method=REQUEST");
                        AlternateView icsView = AlternateView.CreateAlternateViewFromString(meetingInfo, mimeType);
                        MailMessage message = new MailMessage();
                        if (attendees != null)
                        {
                            foreach (string attendee in attendees)
                            {
                                message.To.Add(attendee);
                            }
                        }
                        message.From = new MailAddress(organizer);
                        message.AlternateViews.Add(icsView);
                        using (SmtpClient client = new SmtpClient("MailServerName", 25))
                        {
                            client.Send(message);
                        }
    

    3. 关于From,To,Organizer,Attendees之间的关系

    其实按照步骤1和2,这个例子已经非常完整了,但是也许细心的同学会觉得From,To,Organizer和Attendees的关系是有些不清晰的,需要我们实际的测试一下。以下列出来我详细测试的结论,希望给到大家帮助。

    测试前提:比如我们现在有3个人A,B,C,邮件地址分别是aaa@abc.com, bbb@abc.com, ccc@abc.com

    3-1:MailMessage的From是必须的,如果为空会报错。但是Calendar Meeting Request的接受者并看不到From address的任何信息,接受者看到的是ICS文件中的Organizer。这就使得我们可以用第三方的名义发起一个Calendar Meeting Request。比如我可以写程序以A做为Organizer,B做为Attendee发起一个Calendar Meeting Request,B的Outlook接收以后,在B看来这个Request就是A发出的,看不到我的任何信息。

    3-2:如果C在MailMessage.From,ICS中做为Organizer,A在MailMessage.To里面,但是A和B同时在ICS做为Attendees --- 只有A会收到Request。

    3-3:如果C在MailMessage.From,ICS中做为Organizer,A和B在MailMessage.To里面,A和B同时在ICS做为Attendees --- A和B都会收到Request。

    3-4:如果C在MailMessage.From,ICS中做为Organizer,A和B在MailMessage.To里面,只有A在ICS做为Attendees --- 只有A会收到Request。

    3-5:如果C在MailMessage.From,ICS中做为Organizer,A,B,C在MailMessage.To里面,A,B,C在ICS做为Attendees --- A,B,C都会收到Request。但是在C看来,自己是Organizer,而且自己的名字不会出现在Outlook的Required或者Optional列表中。

    以上结论已经足够我们正常使用,但是我相信理论上的规则会详细复杂的多,如果有同学对这方面非常了解,欢迎补充和指正。

    4. 补充疑问

    还没有解决的问题:Organizer可以收到Request,但是Organizer的Calendar是没有办法被相应Update的。 Outlook发现当前接收者就是Organizer的时候,是不会让accept这个Request的,导致第三方程序用其他人的名义发起一个Request的时候,发起人的Calendar不能被相应更新。这个问题我已经发在MSDN上和stackoverflow上,都没有回应,希望有高手帮助解答。

  • 相关阅读:
    httpclient 发送 json数据,微信security.msgSecCheck,
    win10 输入法,添加美式键盘,调整顺序
    activiti与spring的集成
    spring 中实例化Bean的三种方式
    工作流activiti的HelloWorld
    工作流Activiti的前置准备工作。
    Eclipse中配置约束(DTD,XSD)
    微信开发中,本地缓存,不同步的问题
    微信开发中碰到的坑,json传值,前台遍历json对象,跨页面转值,navigate层级限制
    用pageInfo对List手工分页
  • 原文地址:https://www.cnblogs.com/KeithWang/p/2289913.html
Copyright © 2011-2022 走看看