Retrieve emails in descending/reverse order using MAILKIT c# - c#

I am using mailkit currently to retrieve emails. I am using this code :
var message = inbox.GetMessage(i);
Emails Email = new Emails;
Email.From = message.From.ToString;
Email.EmailDate = message.Date.ToString;
InboxMails.Add(Email);
The problem is, as I am just retrieving the Dates, I can see that the emails are retrieved in the reverse order. I mean, Mailkit fetches the emails from the last email to the first where it should fetch from first to last. E.g. the last email in my mailbox is from 2/3/2014 and the first one is from 1/1/2018.
Now Mailkit loads the last one first and eventually gets to the first one, any way to retrieve in the correct descending order - from the first to the last email?
Also, is there a way to get a Unique Id for each message by which I can find / filter the messages?
I tried this :
for (int i = inbox.Count -1; i >= 0; i--)
But it doesnt even return a single message

Related

IMAP: Query to get all the reply email and get the Id of parent email

I am writing an application to get important emails from separate account and merge it into in a common place.
I want to know all the emails for which we got the replies and want to read those replied emails along with parent email Message Id.
I have simple query on date.
var query = SearchQuery.DeliveredAfter(from)
.And(SearchQuery.DeliveredBefore(to))
And loop through every email and save them in database. But I want to group emails by emails and their replies

Search after multiple criterias with mailkit doesn't work

I have an application that must send some notification emails. After A time if I didn;t get a reply to that mail I must send a reply. Problem appears on the third reply cause the new reply will be sent for both emails sent before. Below are the functions I;ve tried..but none of them seems to work:
SearchQuery.BodyContains(mailid).And(SearchQuery.DeliveredAfter(DateTime.Now.AddMinutes(-10))
SearchQuery.BodyContains(mailid).And(SearchQuery.SentAfter(DateTime.Now.AddMinutes(-10))
SearchQuery.BodyContains(mailid).And(SearchQuery.SentSince(DateTime.Now.AddMinutes(-10))
How can I make to take only the emails sent after the time I give?
IMAP's SEARCH functionality (especially with regards to timespan resolution) is very limited, so you'll probably need to write some client-side logic to filter the messages down to what you actually hope to find.
Start with SearchQuery.BodyContains(mailid) - does that return a list of messages including the one you expect to find?
If not, don't use that search.
To do client-side searching, I would recommend starting with a folder.Fetch() call of whatever subset of messages you can limit it to (and probably fetching at least MessageSummaryItems.Envelope | MessageSummaryItems.UniqueId). The Envelope will give you most of the common message headers that you can then check.
For example:
var uidsWithMailId = folder.Search (SearchQuery.BodyContains (mailid));
var items = folder.Fetch (uidsWithMailId, MessageSummaryItems.UniqueId | MessageSummaryItems.Envelope);
var tenMinutesAgo = DateTime.Now.AddMinutes (-10);
var matches = new UniqueIdSet ();
foreach (var item in items) {
// check if the message was sent within the last 10 minutes
if (item.Envelope.Date >= tenMinutesAgo) {
// add the message UID to our list of matches
matches.Add (item.UniqueId);
}
}

Getting display name from EWS when passing in just an email address

I've using a custom GetMailTips SOAP call (since the EWS for Core 2.0 doesn't support it) to get Out of Office info for a batch of email addresses.
How can I get the display names of the users that I am passing in the email address for?
I can call ResolveName of the managed API and that works but it has to be done one at a time and that is slow. I would like to ideally get this info out when I make my GetMailTips request and failing that make a call with all the email addresses to get the Display Names all at once. I read there is meant to be a ResolveNames method but that's not in the API either.
Any help appreciated
Autodiscover can return that for multiple users eg
AutodiscoverService adService = new AutodiscoverService(ExchangeVersion.Exchange2013_SP1);
adService.Credentials = new NetworkCredential("user#d.com", "pass");
adService.RedirectionUrlValidationCallback = adAutoDiscoCallBack;
List<String> Users = new List<string>();
Users.Add("user1#domain.com");
Users.Add("user2#domain.com");
GetUserSettingsResponseCollection usrSettings = adService.GetUsersSettings(Users, UserSettingName.UserDisplayName);
foreach(GetUserSettingsResponse usr in usrSettings)
{
Console.WriteLine(usr.Settings[UserSettingName.UserDisplayName]);
}
Another way would be to create a Message and add the email address as recipients then save it to the drafts folders and the address should get resolved against the GAL.

Mailkit: fetch messages and copying them to MySQL, attachments to drive

I've been using this code of MailSystem.Net so far to get emails from an Imap INBOX and added options to retrieve mail using $"SENTSINCE {Date}".
string mailBox = "INBOX";
public IEnumerable<Message> GetMailsSince(string mailBox) {
return GetMails(mailBox, $"SENTSINCE {DateTime.Now.AddDays(-3).ToString("dd-MMM-yyyy")}").Cast<Message>();
}
private MessageCollection GetMails(string mailBox, string searchPhrase) {
Mailbox mails = Client.SelectMailbox(mailBox);
MessageCollection messages = mails.SearchParse(searchPhrase);
return messages;
}
But even after studying mailkit for hours I can't seem to distill out how to do the same thing. My goal is to get a list of message object whose properties I can then map to another class I created which writes it into a mysql database. I also want to save the attachments to disk. All this works fine so far but performance is an issue. I'm hoping mailkit will greatly improve that.
My main source has been the sample here but because I'm not familiar with async programming yet and treeviews it's hard to see through it.
How can I hard code that I want "INBOX" as ´IMailFolder´?
Where or how can I use the "SENTSINCE {Date}" filter in Mailkit?
How do I get an ´IEnumerable´ of Mailkits equivalent to the Message object in mailsystem (´IMessageSummary´ maybe)?
If you can point me to some code or even convert the linked MailSystem.Net example to Mailkit that would be fantastic.
MimeMessage is the equivalent of MailSystem.NET's Message object, but that's not what you want. What you want is MailKit's IMessageSummary which will allow you to download individual MIME parts (aka "attachments").
It also allows you to get summary information about the message (flags, received date (aka "InternalDate") pre-parsed/decoded common header values (such as subject, sender, recipients, etc) really quickly because the IMAP server has those pieces of information cached in its database for quick retrieval.
using (var client = new ImapClient ()) {
client.Connect ("imap.mail-server.com", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate ("username", "password");
// if you don't care about modifying message flags or deleting
// messages, you can open the INBOX in read-only mode...
client.Inbox.Open (FolderAccess.ReadOnly);
// search for messages sent since a particular date
var uids = client.Inbox.Search (SearchQuery.SentAfter (date));
// using the uids of the matching messages, fetch the BODYSTRUCTUREs
// of each message so that we can figure out which MIME parts to
// download individually.
foreach (var item in client.Inbox.Fetch (uids, MessageSummaryItems.BodyStructure MessageSummaryItems.UniqueId)) {
foreach (var attachment in item.Attachments.OfType<BodyPartBasic> ()) {
var part = (MimePart) client.Inbox.GetBodyPart (item.UniqueId, attachment);
using (var stream = File.Create (part.FileName))
part.ContentObject.DecodeTo (stream);
}
}
}
Note: Each property on IMessageSummary has a corresponding MessageSummaryItems enum value that you will need to use in order to have that property populated.
For example, if you want to use IMessageSummary.Envelope, you will need to include MessageSummaryItems.Envelope in your Fetch() request.
Since MessageSummaryItems is marked with the [Flags] attribute, you can bitwise-or enum values together like this:
MessageSummaryItems.BodyStructure | MessageSummaryItems.Envelope and both pieces of information will be fetched.
Update:
Here's the inefficient way that is closer to how MailSystem.NET does it.
using (var client = new ImapClient ()) {
client.Connect ("imap.mail-server.com", 993, SecureSocketOptions.SslOnConnect);
client.Authenticate ("username", "password");
// if you don't care about modifying message flags or deleting
// messages, you can open the INBOX in read-only mode...
client.Inbox.Open (FolderAccess.ReadOnly);
// search for messages sent since a particular date
var uids = client.Inbox.Search (SearchQuery.SentAfter (date));
// using the uids of the matching messages, fetch the BODYSTRUCTUREs
// of each message so that we can figure out which MIME parts to
// download individually.
foreach (var uid in uids) {
var message = client.Inbox.GetMessage (uid);
foreach (var attachment in message.Attachments.OfType<MimePart> ()) {
using (var stream = File.Create (attachment.FileName))
attachment.ContentObject.DecodeTo (stream);
}
}
}
Note: if you care about saving message/rfc822 attachments, then take a look at this StackOverflow answer: MailKit save Attachments
The "Inbox" folder is always available on an IMAP mail acccount. With MailKit it is available as ImapClient.Inbox. For the date filtering you could use the DateSearchQuery class. The getting started page of MailKit pretty much covers all your questions.

Internet Message ID FROM EWS Managed API Send Email c#

I am trying to discover if there is a way to determine the internet message ID after sending an email using the EWS Managed API. I understand you can go in there and get the results from the sent box, but the server that is sending these emails is sending multiple emails at a time from different services.
No you can't, basically because EWS sends message Asynchronously the Id isn't available see https://social.msdn.microsoft.com/Forums/azure/en-US/dd034b8c-ffa1-4ae0-9025-45fcf520c9e5/updateitem-does-not-return-itemid?forum=exchangesvrdevelopment
As a work around you might want to consider setting the Internet messageId on the Message before you send it. As long as it valid and unique it should work okay eg
ExtendedPropertyDefinition PidTagInternetMessageId = new ExtendedPropertyDefinition(4149, MapiPropertyType.String);
EmailMessage ema = new EmailMessage(service);
ema.Subject ="test from ews";
ema.Body = new MessageBody("test<br>Rgds<>");
ema.ToRecipients.Add("gscales#domain.com");
ema.SetExtendedProperty(PidTagInternetMessageId,("<" +Guid.NewGuid().ToString() + "#domain.com>"));
ema.SendAndSaveCopy();
Also if you save the message first as a draft before sending it the server will assign the MessageId property which which should then be able to read back using Load.
Cheers
Glen

Categories

Resources