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.