Dieses Wochenende bin ich noch mal das Thema Exchange Webservices angegangen. So richtig steige ich nicht durch die Webservices, zumindest verstehe ich das Verhalten nicht so ganz, oder in der Implementierung sind Fehler. Mein letzter Versuch ging auf die Distributionlists, nun sollen es endlich Emails sein!
Auf jeden Fall wollte ich nun diesmal endlich alle Emails der letzten X-Tage oder sonst was abrufen. Ich hatte mir mehrere Beispiele angeschaut, unter anderem von Stephen Griffin und den Eintrag auf Jive into Messaging world, natürlich gab es noch viele andere Artikel. Der letzte Eintrag diente als Vorlage für meine Anpassungen. Beim Abrufen von Daten kommt bei der FindItem-Methode nur ein Teil der Informationen mit und maximal eine Zusammenfassung des Inhalts. Durch die zusätzliche Eigenschaften fiFindItemRequest.ItemShape.AdditionalProperties kann der Menge an Informationen noch verändert werden. Für mich war das aber nicht so wichtig, ich wollte den gesamten Inhalt, dafür soll man die GetItem-Methde aufrufen. Allerdings wenn ein Extra aufruft gemacht werden muss für die Einträge, so reicht es nur die IDs für den zweiten Aufruf zu sammeln. Alle Anpassungen sind in meinem Code zu sehen.
85 const double MessageWindow = 2;
86 private static void GetLastEmails()
87 {
88 ExchangeServicePortTypeClient exchange = new ExchangeServicePortTypeClient ();
89 exchange.ClientCredentials.Windows.ClientCredential = System.Net. CredentialCache .DefaultNetworkCredentials;
90 ExchangeImpersonationType exExchangeImpersonation = new ExchangeImpersonationType ();
91 ConnectingSIDType csConnectingSid = new ConnectingSIDType ();
92 csConnectingSid.PrimarySmtpAddress = "<email>@capevision.de" ;
93 exExchangeImpersonation.ConnectingSID = csConnectingSid;
94 FindItemType fiFindItemRequest = new FindItemType ();
95 fiFindItemRequest.Traversal = ItemQueryTraversalType .Shallow;
96 ItemResponseShapeType ipItemProperties = new ItemResponseShapeType ();
97 //Load only the message ids for better performance (second request for details required)
98 ipItemProperties.BaseShape = DefaultShapeNamesType .IdOnly; //AllProperties
99 fiFindItemRequest.ItemShape = ipItemProperties;
100
101 //The next 3 blocks load some additional properties with first request
102 PathToExtendedFieldType ptItemURI = new PathToExtendedFieldType ();
103 ptItemURI.PropertyTag = "0x10F3" ;
104 ptItemURI.PropertyType = MapiPropertyTypeType .String;
105
106 PathToExtendedFieldType ptFromEmailDisplay = new PathToExtendedFieldType ();
107 ptFromEmailDisplay.PropertyTag = "0x0C1A" ;
108 ptFromEmailDisplay.PropertyType = MapiPropertyTypeType .String;
109
110 PathToExtendedFieldType ptBodySum = new PathToExtendedFieldType ();
111 ptBodySum.PropertyTag = "0x3FD9" ;
112 ptBodySum.PropertyType = MapiPropertyTypeType .String;
113
114
115 //Limit items to be received
116 PathToUnindexedFieldType StartDateReceivedField = new PathToUnindexedFieldType ();
117 StartDateReceivedField.FieldURI = UnindexedFieldURIType .itemDateTimeReceived;
118 ConstantValueType StartDateReceivedToGet = new ConstantValueType ();
119 StartDateReceivedToGet.Value = DateTime .Now.Subtract( TimeSpan .FromDays(MessageWindow)).ToUniversalTime().ToString( "u" );
120 FieldURIOrConstantType StartDateReceivedConstant = new FieldURIOrConstantType ();
121 StartDateReceivedConstant.Item = StartDateReceivedToGet;
122 IsGreaterThanOrEqualToType igtett = new IsGreaterThanOrEqualToType ();
123 igtett.FieldURIOrConstant = StartDateReceivedConstant;
124 igtett.Item = StartDateReceivedField;
125 RestrictionType rt = new RestrictionType ();
126 rt.Item = igtett;
127 fiFindItemRequest.Restriction = rt;
128
129 DistinguishedFolderIdType [] faFolderIDArray = new DistinguishedFolderIdType [2];
130 faFolderIDArray[0] = new DistinguishedFolderIdType ();
131 faFolderIDArray[0].Id = DistinguishedFolderIdNameType .inbox; //only load Inbox-items
132 //fiFindItemRequest.ItemShape.AdditionalProperties = new BasePathToElementType[3];
133 //fiFindItemRequest.ItemShape.AdditionalProperties[0] = ptBodySum;
134 //fiFindItemRequest.ItemShape.AdditionalProperties[1] = ptItemURI;
135 //fiFindItemRequest.ItemShape.AdditionalProperties[2] = ptFromEmailDisplay;
136 fiFindItemRequest.ParentFolderIds = faFolderIDArray;
137 FindItemResponseType frFindItemResponse;
138 int emails = 0;
139 int errors = 0;
140 try
141 {
142 exchange.FindItem( null , null , Thread .CurrentThread.CurrentUICulture.ToString(), null , fiFindItemRequest, out frFindItemResponse);
143 foreach ( FindItemResponseMessageType firmtMessage in frFindItemResponse.ResponseMessages.Items)
144 {
145 if (firmtMessage.RootFolder.TotalItemsInView > 0)
146 {
147 foreach ( ItemType miMailboxItem in (( ArrayOfRealItemsType )firmtMessage.RootFolder.Item).Items)
148 {
149 //if (miMailboxItem.ExtendedProperty != null)
150 //{
151 // if (miMailboxItem.ExtendedProperty.Length == 3)
152 // {
153 emails++;
154 //TODO: Create item batches for effective download
156 try
157 {
158 GetItemResponseType giResponse;
159 giResponse = GetCurrentItem(exchange, miMailboxItem);
160 if (giResponse != null && giResponse.ResponseMessages != null && giResponse.ResponseMessages.Items.Count() > 0)
161 {
162 ItemType [] array = (( ItemInfoResponseMessageType )giResponse.ResponseMessages.Items[0]).Items.Items;
163 foreach ( ItemType t in array)
164 {
165 MessageType details = t as MessageType ;
166 if (details == null )
167 {
168 //This is not a mail item
169 //should i handle this?
170 }
171 else
172 {
173 Console .WriteLine( "[{0}] - <{1}>{2} - {3}" , details.DateTimeReceived.ToString( "u" ), details.From.Item.Name, details.From.Item.EmailAddress, details.Subject.ToString());
174 //if (details.Body != null)
175 // Console.WriteLine(details.Body.Value);
176 }
177 }
178 }
179 }
180 catch ( Exception ex)
181 {
182 errors++;
183 Console .WriteLine( "[{0}] - <{1}> - {2}" , miMailboxItem.DateTimeReceived.ToString( "u" ),
miMailboxItem.DisplayTo, miMailboxItem.ItemId.Id);
184 Console .WriteLine( "--Error receiving item: " + ex.Message);
185 }
186 //only default, then no email address loaded (and some other properties)
189 // }
190 //}
191 }
192 }
193 }
194 }
195 catch ( Exception ex)
196 {
197 Console .WriteLine(ex.ToString());
198 throw ;
199 }
200 Console .WriteLine( "Emails received {0}, errors {1}" , emails, errors);
201 }
203 private static GetItemResponseType GetCurrentItem( ExchangeServicePortTypeClient exchange, ItemType miMailboxItem)
204 {
205 GetItemResponseType giResponse;
206 GetItemType giType = new GetItemType ();
207 giType.ItemShape = new ItemResponseShapeType ();
208 giType.ItemShape.BaseShape = DefaultShapeNamesType .Default;
209 giType.ItemShape.IncludeMimeContent = true ;
210 giType.ItemShape.IncludeMimeContentSpecified = false ;
211 giType.ItemShape.BodyType = BodyTypeResponseType .Text; // miMailboxItem.Body.BodyType1;
212 giType.ItemShape.BodyTypeSpecified = true ;
213 ItemIdType current = new ItemIdType ();
214 current.Id = miMailboxItem.ItemId.Id.ToString();
215 giType.ItemIds = new ItemIdType [] { current };
216 exchange.GetItem( null , null , null , null , giType, out giResponse);
217 return giResponse;
218 }
Ende Bei einigen Versuchen erhielt ich die Fehlermeldung, dass er Response zu groß war, allerdings gab es dafür eine schnelle Abhilfe, einfach die Verarbeitung des Responses auf Streaming umstellen.
19 < binding name = " ExchangeServiceBinding " closeTimeout = " 00:01:00 "
20 openTimeout = " 00:01:00 " receiveTimeout = " 00:10:00 " sendTimeout = " 00:01:00 "
21 allowCookies = " false " bypassProxyOnLocal = " false " hostNameComparisonMode = " StrongWildcard "
22 maxBufferSize = " 65536 " maxBufferPoolSize = " 524288 " maxReceivedMessageSize = " 655369 "
23 messageEncoding = " Text " textEncoding = " utf-8 " transferMode = " StreamedResponse "
24 useDefaultWebProxy = " true " >
25 < readerQuotas maxDepth = " 32 " maxStringContentLength = " 8192 " maxArrayLength = " 16384 "
26 maxBytesPerRead = " 4096 " maxNameTableCharCount = " 16384 " />
27 < security mode = " Transport " >
28 <!-- <transport clientCredentialType="Windows" proxyCredentialType="None" /> -->
29 < transport clientCredentialType = " Ntlm " proxyCredentialType = " None " />
30 < message clientCredentialType = " UserName " algorithmSuite = " Default " />
31 </ security >
32 </ binding >
Mein größtes Problem ist allerdings, dass die GetItem-Methode für einige Mails immer mal wieder einen Fehler wirft. Leider bekomme ich den Fiddler auch nicht zur Arbeit mit dem Exchange überredet, da bei uns nur HTTPs zulässig ist. Falls jemand einen Tipp für mich hat, was das sein kann, wäre ich sehr dankbar. Da in den meisten Fällen die Email erfolgreich verarbeitet werden kann, kann man die Lösung durchaus zum Verarbeiten nutzen. Mich ärgert allerdings trotzdem, dass Emails nicht korrekt herausgeschrieben werden.
In meinem Code sollte noch einige Funktionen optimiert werden. Zum einen sollte man mehrere Items mit einer Anfrage abrufen, da jeder Abruf ein Roundtrip mit dem Server erfordert. Des Weiteren muss das ErrorHandling deutlich verbessert werden, aber Schritt für Schritt.
1 Kommentar:
Hi,
es fällt auf, dass Du eine Objekt der Klasse ExchangeImpersonation instanziierst, dieses Objekt aber nicht zuweist:
esb.ExchangeImpersonation = exExchangeImpersonation;
Somit dürfte mindestens der Zugriff auf E-Mails fremder Postfächer fehlschlagen.
Viele Grüße
Volker
Kommentar veröffentlichen