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.
Related
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);
}
}
I want to forward an email after add some comment to that. original email saved as eml file so first i load that file and then add my comment to body or attach some new files and then resend email to new email address.
var mail = new MimeKit.MimeMessage();
var file = System.IO.File.ReadAllBytes("sample.eml"));
var orgMessage = new MimeKit.MimeMessage(file);
var builder = new MimeKit.BodyBuilder();
builder.TextBody = "user comment";
builder.Attachments.Add(new MimeKit.MessagePart { Message = orgMessage });
mail.Body = builder.ToMessageBody();
First of all in line 3 i get this error:
Unknown initialization parameter: System.Byte[]
Second I read this great answer Forward email using MailKit (C#) and what is resent parameters for? if i set them my comment on forwarded email not set? and that email resent clearly without any change?
Unknown initialization parameter: System.Byte[]
This means that there is no MimeMessage constructor that takes a byte[] parameter.
In other words, you can't do this:
var file = System.IO.File.ReadAllBytes("sample.eml"));
var orgMessage = new MimeKit.MimeMessage(file);
The correct way to load a message from a file is to do this:
var orgMessage = MimeMessage.Load ("sample.eml");
Second I read this great answer Forward email using MailKit (C#) and what is resent parameters for? if i set them my comment on forwarded email not set? and that email resent clearly without any change?
The MimeMessage.Resent* properties are used only when forwarding a message without attaching it to a new message.
You need to pick only 1 of the 3 solutions in the answer of mine that you linked to.
If you are going to attach the original message (like you are doing), then you SHOULD NOT use the Resent properties of the MimeMessage.
I have an email with yahoo business and MailKit works with POP. I want to download the message after finding a specific subject. Or could I use IMAP?
If the POP3 server supports the TOP extension, you can download just the message headers to first check the subject. To do that, you could do something like this:
if (client.Capabilities.HasFlag (Pop3Capabilities.Top)) {
var headers = client.GetMessageHeaders (index);
if (headers[HeaderId.Subject] == subject)
message = client.GetMessage (index);
}
If your Yahoo account also supports IMAP, I would recommend using IMAP since IMAP allows you to query the server for messages with a given subject which is much more efficient than downloading the headers for every message to check if the subject matches the one you are looking for.
I'm working on a WinForms Application that uses EWS to read mails of our Exchange Server. The Exchange is at Version 2007. I could successfully read, move, delete and send emails through EWS. I'm using Autodiscover to authenticate and select the Mailbox. The only problem is that I never get any sender e-mail address. The only thing I get is the name of the sender but no address.
This is my code so far:
Service1 = new ExchangeService(ExchangeVersion.Exchange2007_SP1);
Service1.Credentials = new WebCredentials(Properties.Settings.Default.Username, Properties.Settings.Default.Password);
Service1.Url = new Uri(Properties.Settings.Default.Serviceurl);
EmailMessage messageAtt = EmailMessage.Bind(Service1, item.Id, new PropertySet(BasePropertySet.IdOnly, ItemSchema.Attachments, ItemSchema.HasAttachments, EmailMessageSchema.IsRead));
EmailMessage messageData = (EmailMessage)item;
foreach (Attachment attachment in messageAtt.Attachments)
{
String from = messageData.Sender.Address.ToString();
}
This is what I get when I debug:
Can anyone give me a suggestion what I am mistaking here? Is there a Problem with what I wrote or could it even be a set up problem of the exchange Server?
The problem seems to be the definition of the EmailMessage object:
By defining the EmailMessage with explicit conversion not all attributes are geting transfered to the new object. If you try it with the upper EmailMessage object which gets defined by the .Bind() method, it wont work either. The reason that happens is due to the PropertySet passed as 3rd parameter. The only solution I found is to create a 3rd object:
EmailMessage messageInfo = EmailMessage.Bind(useService, item.Id);
The disadvantage of this Object is, that you won't be able to see if the item has an attachement or not.
Hope this helps anyone not wasing his time on a stupid mistake like that ;)
I want to create window application through which i can read email from gmail.
Actually i want to read proper format of email like to,from,subject,cc and body.
using (Imap imap = new Imap())
{
imap.ConnectSSL("mail.company.com");
imap.Login("angel_y#company.com", "xyx***");
imap.SelectInbox();
List<long> uids = imap.SearchFlag(Flag.Unseen);
foreach (long uid in uids)
{
string eml = imap.GetMessageByUID(uid);
IMail message = new MailBuilder()
.CreateFromEml(eml);
Console.WriteLine(message.Subject);
Console.WriteLine(message.TextDataString);
}
imap.Close(true);
}
It is this error.
No connection could be made because the target machine actively refused it
Try this I have added the Port number along with the gmail imap server for connection to the server
using (Imap imap = new Imap())
{
imap.ConnectSSL("imap.gmail.com", 993);
imap.Login("angel_y#company.com", "xyx***"); // MailID As Username and Password
imap.SelectInbox();
List<long> uids = imap.SearchFlag(Flag.Unseen);
foreach (long uid in uids)
{
string eml = imap.GetMessageByUID(uid);
IMail message = new MailBuilder()
.CreateFromEml(eml);
Console.WriteLine(message.Subject);
Console.WriteLine(message.TextDataString);
}
imap.Close(true);
}
I am sure there are many libraries to do this. A quick search turned this up:
http://code.msdn.microsoft.com/CSharpGmail
And here is a gadget / widget app that has some code to do this:
http://www.codeproject.com/KB/gadgets/GadgetInterop.aspx
You may need to make sure you are using the correct hostname and port number. Configuring these settings will depend on the IMAP API you are using for .Net
But the settings you want to use are listed on google's site.
IMAP => imap.google.com:993 (SSL)
SMTP => smtp.google.com:587 (TLS)
gmail offers access via its config page to pull down emails through POP3/IMAP. Here are a few such links I found off of Google that could be used for IMAP access.
http://www.codeproject.com/KB/IP/imaplibrary.aspx
Accessing Imap in C#
http://koolwired.com/solutions/solutions.aspx?id=30
Hopefully that helps!