GetMessage() take excessive long time MailKit - c#

When I call
var result = MailKit.GetMessage(uid)
Then the call takes around 4 seconds to return. Is there any better/faster way to get the mime message from the server??
Currently doing the following:
1. Fetch(0, -1, MessageSummaryItems.UniqueId | MessageSummaryItems.Envelope | MessageSummaryItems.Flags)
2. Loop the fetch result to find a messageId match
3. Send GetMessage() with the UID found previously.
I can see that FETCH in most cases takes around 2 secs, all in all my process will take something like 6 seconds, which is kinda "long" before I can present the email in the client.
Is there a faster way to get a mime message from a mail server using MailKit, when all I know about the email is the MessageID??

You could cache all of the message summaries so that you don't have to ask the server for them each time...
You could also try:
var uids = folder.Search (SearchQuery.HeaderContains ("Message-Id", messageId));
if (uids.Count > 0)
message = folder.GetMessage (uids[0]);

Related

EWS: Search in email body only responses 250 results

I currently got a problem with the exchange web service in C#.
I'm trying to loop through mails that are older than 3 months, but I only get 250 mails back. In the folder are more than 80.000 mails so that isn't the correct count.
After searching for the problem I now know that the service only gives me 250 results per page. But the TotalCount is 250 too, so I can't work with paging because there is no second page. Without the body filter it works and I get back like 70.000 mails which is correct. Has anyone had the same problem and can help me?
Currently the programm just uses 2 filters with the SearchFilter And operator and orders the result ascending.
Here is my current code for getting the mails:
Folder folder; // folder from loop
DateTime dateStart; // = today - 3 months
SearchFilter.SearchFilterCollection filter = new SearchFilter.SearchFilterCollection(LogicalOperator.And);
filter.Add(new SearchFilter.IsLessThanOrEqualTo(EmailMessageSchema.DateTimeReceived, dateStart));
filter.Add(new SearchFilter.ContainsSubstring(ItemSchema.Body, "test"));
ItemView view = new ItemView(1000, 0, OffsetBasePoint.Beginning);
// Get oldest first
view.PropertySet = new PropertySet(BasePropertySet.IdOnly, ItemSchema.DateTimeReceived);
view.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
view.Traversal = ItemTraversal.Shallow;
FindItemsResults<Item> findResults = exchangeService.FindItems(folder.Id, filter, view);
findResults.TotalCount() // = 250
I would be glad about a solution, thanks for helping :)
Am sure you have figured this out by now, but it is due to EWS throttling. While this can be changed, it is not advised. Only workaround I have found is to move the items to another folder and keep re-running logic. Here is a link to info on EWS throttling and also a way to determine your current policy - https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/ews-throttling-in-exchange.

Fetching size of message using IMAP command

I am fetching the size of message using following IMAP command.
"$ FETCH UID RFC822.SIZE\r\n"
For some messages the command works properly and returns the message size
"* 3 FETCH (RFC822.SIZE 2376)\r\n$ OK Success\r\n"
But for some emails its not fetching the size of message. It returns only Success message but not the size
Here is the response for some messages.
"$ OK Success\r\n"
Is there any alternative way for fetching the size of message?
Stepping out on a limb... what you have in mind is x uid fetch 1234 rfc822.size in order to learn the size of the message with UID 1234. However, what you send is y fetch 1234 rfc822.size, and if there are fewer than 1234 messages in the mailbox that command will not work.
Am I guessing correctly?
If you get no size information back, then it means that the message doesn't exist.

How to delete the Mail Programmatically in IMAP or POP using C#

This is my code to delete the mail. But, it doest working,
public object Delete(int index)
{
StreamWriter.WriteLine("$ DELE {0}"+index);
StreamWriter.Flush();
return Response();
}
private string Response()
{
byte[] data = new byte[TcpClient.ReceiveBufferSize];
int ret = NetworkStream.Read(data, 0, data.Length);
return Encoding.ASCII.GetString(data).TrimEnd();
}
Why are you adding these two items together:
StreamWriter.WriteLine("$ DELE {0}"+index);
Surely you mean something like this:
StreamWriter.WriteLine(String.Format("$ DELE {0}",index));
That said, this doesn't look like a valid IMAP command anyway. This looks more like POP, and even then, you shouldn't have a $ in the command string. What specification are you following?
If you're connected to a POP3 server, the command should look something like this:
StreamWriter.WriteLine(String.Format("DELE {0}",index));
If you're connected to an IMAP server, I believe deleting requires first flagging the message as deleted, and then expunging it. Also, all commands in IMAP require a unique identifier which you will need to generate. From the spec:
Each client command is prefixed with an identifier (typically a short alphanumeric string, e.g., A0001, A0002, etc.) called a "tag". A different tag is generated by the client for each command.
Then to flag a message as deleted you would do something like this:
A003 STORE 35 +FLAGS (\Deleted)
Where A003 is the tag prefix, and 35 is the sequence number of the message you want to delete. But then to permanently delete all flagged messages you'll also need to send and EXPUNGE command, that might look like this:
A004 EXPUNGE
Note that EXPUNGE will potentially result in message sequence numbers changing so you can't assume that the message associated with a particular sequence number will be the same after the EXPUNGE command has completed.

Messages getting overwritten on IBM MQ

I am sending 3 messages
Message1 - correlation id:5000
empty message (no body/message)-correlation id:5001
Message2 - correlation id:5002
My outbound queue processes like this
Message1 - correlation id:5000
Message1-correlation id:5001 => same previous message ovewritten on the empty message.*
Message2 - correlation id:5002
The second line above should not have had Message1, instead just empty. Any thoughts?
My get method
mqGetMsgOpts = new MQGetMessageOptions();
if (mqQueue != null)
{
//Get options for the messsage
mqGetMsgOpts.Options = MQC.MQGMO_BROWSE_FIRST | MQC.MQGMO_WAIT | MQC.MQOO_INQUIRE;
mqGetMsgOpts.MatchOptions = MQC.MQMO_NONE;
mqGetMsgOpts.WaitInterval = 5000; // 5 seconds limit for waiting
}
if (mqMsg.MessageLength > 0 && mqMsg.DataLength > 0)
{
messageData = mqMsg.ReadString(mqMsg.MessageLength);
}
If I don't do the length check, i will get stream reader related exception.
My put method
if(mqQueue==null)
mqQueue = mqQMgr.AccessQueue("Queue Name", MQC.MQOO_OUTPUT | MQC.MQOO_INPUT_SHARED | MQC.MQOO_INQUIRE);
mqMsg.WriteString(message);
I have not heard messages getting overwritten in WMQ. I suspect this must be an issue with application. This line of code:
mqGetMsgOpts.Options = MQC.MQGMO_BROWSE_FIRST | MQC.MQGMO_WAIT | MQC.MQOO_INQUIRE;
The MQC.MQGMO_BROWSE_FIRST option will make WMQ to return always the first message that satisfies the conditions specified in MQMD structure. I can't make out from your code snippet if this option is modified at a later point to specify MQGMO_BROWSE_NEXT to read the next message in the queue.
Instead of MQC.MQGMO_BROWSE_FIRST you can specify MQGMO_BROWSE_NEXT option to continuously read messages.
Also you have specified MQC.MQOO_INQUIRE which is not valid for GMO options. You need to remove that.
More details browse options are here
I can imagine two possible issues that could cause this.
Your putting application did not send an empty message body for message two.
Your getting application is showing you the message buffer from message one. If there is no message buffer delivered from MQ, your previous message buffer contents will remain.
To determine which has happened to you I suggest you put all the messages, but before running your sample to get them, instead run something like the supplied sample amqsget to rule out the possibility of 1.
Then you can focus on the get buffer in your application. Make sure you are not using it if MQ said the length of the returned message is zero.

Download emails (backup) from gmail programmatically

Does anyone know a way to execute a bulk dump of every email of a gmail account and write the emails to a file?
I'm looking to write a program that would let users back up there gmail (probably via imap) and back it up to either individual files or as a pst (I know pst will probably be much harder)
some time ago I wrote a blog post about exactly same topic. See HOWTO: Download emails from a GMail account in C# for details.
Code uses our Rebex Mail component:
using Rebex.Mail;
using Rebex.Net;
...
// create the POP3 client
Pop3 client = new Pop3();
try
{
// Connect securely using explicit SSL.
// Use the third argument to specify additional SSL parameters.
Console.WriteLine("Connecting to the POP3 server...");
client.Connect("pop.gmail.com", 995, null, Pop3Security.Implicit);
// login and password
client.Login(email, password);
// get the number of messages
Console.WriteLine("{0} messages found.", client.GetMessageCount());
// -----------------
// list messages
// -----------------
// list all messages
ListPop3MessagesFast(client); // unique IDs and size only
//ListPop3MessagesFullHeaders(client); // full headers
}
finally
{
// leave the server alone
client.Disconnect();
}
public static void ListPop3MessagesFast(Pop3 client)
{
Console.WriteLine("Fetching message list...");
// let's download only what we can get fast
Pop3MessageCollection messages =
client.GetMessageList(Pop3ListFields.Fast);
// display basic info about each message
Console.WriteLine("UID | Sequence number | Length");
foreach (Pop3MessageInfo messageInfo in messages)
{
// display header info
Console.WriteLine
(
"{0} | {1} | {2} ",
messageInfo.UniqueId,
messageInfo.SequenceNumber,
messageInfo.Length
);
// or download the whole message
MailMessage mailMessage = client.GetMailMessage(messageInfo.SequenceNumber);
}
}
Gmail provides POP access. So just use any library that allows you to communicate using POP and you're golden.
Edit: I just noticed that you mentioned IMAP; I recommend you use POP instead for bulk dumps. IMAP is too chatty for what you want to do.
If you must use IMAP, here's a library for you.
You can use fetchmail from a Unix environment to create an mbox file.
http://lifehacker.com/software/gmail/geek-to-live--back-up-gmail-with-fetchmail-235207.php
There is an open-source Python program compiled to Windows (using py2exe) at
https://github.com/jay0lee/got-your-back/wiki
But Mac users would need to compile it (which I haven't completely figured out due to a py2exe error).
Either way, you also need a way to execute the program automatically in a schedule.

Categories