zoukankan      html  css  js  c++  java
  • Exchange学习:EWS 通过流通知和拉取通知订阅Exchange新邮件提醒

    原理

    EWS 通知以订阅的形式进行。 通常,每个邮箱一个订阅,在邮箱订阅内你还可以订阅一些或所有文件夹。 你可以决定订阅什么种类的通知(流式、拉取、推送)以及接收什么种类的事件(NewMail、Created、Deleted、Modified等),然后可以创建订阅。 然后 EWS 事件会非同步地从邮箱服务器发送到客户端。

    EWS流式通知和拉取通知区别

    流式通知依赖于一个在服务器挂起的 get 请求来保持流式订阅连接打开,这样任何在连接活动时发生的事件都会马上流给客户端。 多个通知可以在单个连接周期内发送,在至多 30 分钟的间隔期过期前,连接都会保持打开。 连接过期后,客户端再次发送 get 请求。 下面显示了流式订阅和流式通知工作的原理。

    流式通知概述

    拉取通知依靠客户端以一定间隔请求客户端管理的通知。 这可能会在获得 GetEvents 响应时未收到通知。 下面显示了拉取订阅和拉取通知工作的原理。

    拉取通知概述

    拉取通知代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    using System.Timers;
    using Microsoft.Exchange.WebServices.Data;
    
    namespace SubscribeToPullNotifications
    {
        class Program
        {
            static ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
            static PullSubscription Subscription;
            static void Main(string[] args)
            {
                System.Net.ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
                SubscribePullNotifications(WellKnownFolderName.Inbox);
                Timer t = new Timer();
                t.Elapsed += t_Elapsed;
                t.Interval = 5000;
                t.Start();
                Console.Read();
            }
    
            static void t_Elapsed(object sender, ElapsedEventArgs e)
            {
                Console.WriteLine("程序运行中");
                GetPullNotifications();
            }
            public static void SubscribePullNotifications(FolderId folderId)
            {
                service.Url = new Uri("https://xxx.xxx.xxx.xxx/EWS/Exchange.asmx");
                service.Credentials = new NetworkCredential("xxx@xxx.xxx", "xxx");
                Subscription = service.SubscribeToPullNotifications(new FolderId[] { folderId }, 1440, null, EventType.NewMail, EventType.Created, EventType.Deleted, EventType.Moved);
            }
            public static void GetPullNotifications()
            {
                IEnumerable<ItemEvent> itemEvents = Subscription.GetEvents().ItemEvents;
                IEnumerable<FolderEvent> folderEvents = Subscription.GetEvents().FolderEvents;
                foreach (ItemEvent itemEvent in itemEvents)
                {
                    switch (itemEvent.EventType)
                    {
                        case EventType.Copied:
                            Console.WriteLine("ItemEvent Copied");
                            break;
                        case EventType.Created:
                            Console.WriteLine("ItemEvent Created");
                            break;
                        case EventType.Deleted:
                            Console.WriteLine("ItemEvent Deleted");
                            break;
                        case EventType.FreeBusyChanged:
                            Console.WriteLine("ItemEvent FreeBusyChanged");
                            break;
                        case EventType.Modified:
                            Console.WriteLine("ItemEvent Modified");
                            break;
                        case EventType.Moved:
                            Console.WriteLine("ItemEvent Moved");
                            break;
                        case EventType.NewMail:
                            Console.WriteLine("ItemEvent New mail");
                            Console.WriteLine(itemEvent.ItemId.UniqueId);
                            EmailMessage emailMessage = EmailMessage.Bind(service, itemEvent.ItemId.UniqueId);
                            Console.WriteLine(emailMessage.Subject);
                            Console.WriteLine(emailMessage.Body.Text);
                            Console.WriteLine(emailMessage.From);
                            Console.WriteLine(emailMessage.DateTimeReceived);
                            Console.WriteLine(string.Join(";", emailMessage.ToRecipients.Select(x => x.Address).ToArray()));
                            Console.WriteLine(string.Join(",", emailMessage.CcRecipients.Select(u => u.Address).ToArray()));
                            break;
                        case EventType.Status:
                            Console.WriteLine("ItemEvent Status");
                            break;
                        default:
                            break;
                    }
    
                    foreach (var folderEvent in folderEvents)
                    {
                        switch (folderEvent.EventType)
                        {
                            case EventType.Copied:
                                Console.WriteLine("FolderEvent Copied");
                                break;
                            case EventType.Created:
                                Console.WriteLine("FolderEvent Created");
                                break;
                            case EventType.Deleted:
                                Console.WriteLine("FolderEvent Deleted");
                                break;
                            case EventType.FreeBusyChanged:
                                Console.WriteLine("FolderEvent FreeBusyChanged");
                                break;
                            case EventType.Modified:
                                Console.WriteLine("FolderEvent Modified");
                                break;
                            case EventType.Moved:
                                Console.WriteLine("FolderEvent Moved");
                                break;
                            case EventType.NewMail:
                                Console.WriteLine("FolderEvent NewMail");
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
    
        }
    }

    流通知:

            public void SyncGet()
            {
                _service = InitService(_service);
                // Subscribe to pull notifications in the Inbox.
                PullSubscription subscription = _service.SubscribeToPullNotifications(
                    new FolderId[] { WellKnownFolderName.Inbox }, 30, null,
                    EventType.NewMail, EventType.Created, EventType.Deleted,
                    EventType.Modified, EventType.Moved, EventType.Copied, EventType.FreeBusyChanged);
    
                // Call GetEvents to retrieve events from the server. 
                GetEventsResults events = subscription.GetEvents();
            }
    
            public void SyncEmail()
            {
                _service = InitService(_service);
                // Subscribe to streaming notifications in the Inbox. 
                var StreamingSubscription = _service.SubscribeToStreamingNotifications(
                    new FolderId[] { WellKnownFolderName.Inbox },
                    EventType.NewMail,
                    EventType.Created,
                    EventType.Deleted,
                    EventType.Modified,
                    EventType.Moved,
                    EventType.Copied,
                    EventType.FreeBusyChanged);
    
                // Create a streaming connection to the service object, over which events are returned to the client.
                // Keep the streaming connection open for 30 minutes.
                StreamingSubscriptionConnection connection = new StreamingSubscriptionConnection(_service, 30);
                connection.AddSubscription(StreamingSubscription);
                connection.OnNotificationEvent += OnNotificationEvent;
                connection.OnDisconnect += OnDisconnect;
                connection.Open();
            }
    
    
            private void OnDisconnect(object sender, SubscriptionErrorEventArgs args)
            {
                SyncEmail();
            }
    
            private void OnNotificationEvent(object sender, NotificationEventArgs args)
            {
                if (args != null)
                {
                    foreach (NotificationEvent notificationEvent in args.Events)
                    {
                        if (notificationEvent is ItemEvent)
                        {
                            ItemEvent itemEvent = (ItemEvent)notificationEvent;
                            Console.WriteLine(notificationEvent.EventType.ToString());
                            Item item = Item.Bind(_service, itemEvent.ItemId);
                            switch (notificationEvent.EventType)
                            {
                                case EventType.Moved:
                                    Console.WriteLine(item.Subject);
                                    break;
                                case EventType.NewMail:
                                    Console.WriteLine(item.Subject);
                                    break;
                                case EventType.Created:
                                    Console.WriteLine($"创建:{item.Subject}");break;
                                case EventType.Deleted:
                                    Console.WriteLine($"删除:{item.Subject}");
                                    break;
                                default:
                                    break;
                            }
                        }
    
                    }
                }
            }

    另外事件分为ItemEvents和FolderEvents,具体区别可以看下图:

     现实中,多个通知(甚至是多个同类型的通知)可以由单一用户操作创建。 比如,在文件夹移动操作的情况中,三个文件夹事件被创建:一个关于文件夹修改,一个关于旧文件夹,还有一个关于新文件夹。 因为单一操作可以出现多个事件,所以要创建一个等待事件,这样同步只有在操作完成时才会进行,而不是在操作中多次进行。

    如果遇到证书问题则需要在程序中加入:

                System.Net.ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack;
      
    private static bool CertificateValidationCallBack(
     object sender,
     System.Security.Cryptography.X509Certificates.X509Certificate certificate,
     System.Security.Cryptography.X509Certificates.X509Chain chain,
     System.Net.Security.SslPolicyErrors sslPolicyErrors)
            {
                // If the certificate is a valid, signed certificate, return true.
                if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None)
                {
                    return true;
                }
    
                // If there are errors in the certificate chain, look at each error to determine the cause.
                if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
                {
                    if (chain != null && chain.ChainStatus != null)
                    {
                        foreach (System.Security.Cryptography.X509Certificates.X509ChainStatus status in chain.ChainStatus)
                        {
                            if ((certificate.Subject == certificate.Issuer) &&
                                (status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.UntrustedRoot))
                            {
                                // Self-signed certificates with an untrusted root are valid. 
                                continue;
                            }
                            else
                            {
                                if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags.NoError)
                                {
                                    // If there are any other errors in the certificate chain, the certificate is invalid,
                                    // so the method returns false.
                                    return false;
                                }
                            }
                        }
                    }
    
                    // When processing reaches this line, the only errors in the certificate chain are 
                    // untrusted root errors for self-signed certificates. These certificates are valid
                    // for default Exchange server installations, so return true.
                    return true;
                }
                else
                {
                    // In all other cases, return false.
                    return false;
                }
            }

    注意这个不要在正式环境使用。

    参考自:https://docs.microsoft.com/zh-cn/exchange/client-developer/exchange-web-services/notification-subscriptions-mailbox-events-and-ews-in-exchange

  • 相关阅读:
    ACCP7.0-S2-复习自测-15测试分析
    线程
    多线程下的单例模式
    combobox 属性、事件、方法
    java的多线程总结
    爬虫--登录网页
    shell--字符串是否为空
    python--正则表达式 字符串匹配
    mysql---表所在数据库
    python--日期操作
  • 原文地址:https://www.cnblogs.com/DarkRoger/p/14700712.html
Copyright © 2011-2022 走看看