C#: How to keep track of the UID of messages between folders? - c#

I'm moving messages from the inbox folder to a new folder. After a while I need to move some of these messages(not all) to a new folder. The problem with this is that everytime I move a message the uid changes. How can I do this without moving the wrong message?

If your server supports UIDPLUS (nearly all do), and you yourself are moving or copying the messages, the server will give you the new UID when you copy or move it in the COPYUID response. You'll need to record this.
An example from the IMAP MOVE RFC6851:
C: a UID MOVE 42:69 foo
S: * OK [COPYUID 432432 42:69 1202:1229]
S: * 22 EXPUNGE
S: (more expunges)
S: a OK Done
The COPYUID response includes the UIDVALIDITY of the destination mail box, the UID set of the source messages, and the UID set of the destination messages.
If some other process is doing the moving, there's no way to guarantee the same message, and you'd have to track them based on their content (eg, the Message-ID header, the date time, a hash, etc.)

You're "moving" also involves an INSERT into DB to keep track of UIDs? If yes, watch for autogenerated PKs.

Related

MailKit: Message not delete from Inbox when gmail setting Conversation view on

I'm working with MailKit lib and have a problem.
My application is read specify email in Inbox (Gmail), and delete them.
IList<UniqueId> listUid = inbox.Search(query);
for (int i = 0; i < listUid.Count; i++)
{
var message = inbox.GetMessage(listUid[i]);
inbox.AddFlags(msg.Uid, MessageFlags.Deleted, true);
inbox.Expunge();
}
It run OK, But when Gmail setting Conversation View = Conversation view on, the message that marked as deletion will comback in Inbox if have same email subject and same sender. In next-time I count message, all of deletion message will be re-count. How to avoid it? (save Uid of deletion message is one way but when message number increase, processing will be slow)
Thanks very much.
GMail unfortunately does not behave the same way most other IMAP servers behave and so when you mark a message as \Deleted, it gets moved to the Trash folder automatically and so the Expunge does nothing.
What you need to do is go to your GMail settings and change the behavior of your IMAP account so that it doesn't move the messages to Trash.
Either that or MoveTo() the message to the Trash folder yourself so you can get the UID of the message in the Trash folder (hint: use the return value of the MoveTo() method) and then open the Trash folder and expunge the message from there.
Note: this code is untested, but it should look something like this:
var trash = client.GetFolder (SpecialFolder.Trash);
var moved = client.Inbox.MoveTo (uid, trash);
if (moved.HasValue) {
trash.Open (FolderAccess.ReadWrite);
trash.AddFlags (moved.Value, MessageFlags.Deleted, true);
trash.Expunge (new [] { moved.Value });
}

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.

Unable to delete or move a message via IMAP

I am trying to move a message to another folder in a mail box using the IMAP functionality of ae.net.mail. The problem is that although the message is moved into the target folder, it is not removed from INBOX.
I'm also having a problem deleting a message. In this case I'm finding that the status of the message merely changes from unseen to seen.
Here is what I have tried:
using (ImapClient ic = new ImapClient(
host, email, password, ImapClient.AuthMethods.Login, 993, true))
{
ic.SelectMailbox("INBOX");
string[] uids = ic.Search(SearchCondition.From("someone#gmail.com"));
MailMessage[] messages =
ic.GetMessages(uids[0], uids[uids.Length - 1], false);
ic.MoveMessage(uids[0], "Junk");
}
The standard IMAP protocol does not have a MOVE command (but there is an extension that adds it). So, depending on your IMAP server, the client may need to implement MOVE as a UID COPY + UID STORE +FLAGS.SILENT (\Deleted) + UID EXPUNGE, but that assumes that the server supports the UIDPLUS extension. If the server doesn't support UIDPLUS, either, then it becomes essentially impossible to implement properly. All you can do is COPY + STORE +FLAGS.SILENT (\Deleted) but cannot do the EXPUNGE because there's no way to limit the messages that will get expunged (I suppose you could unmark any other deleted messages, then EXPUNGE, then re-mark them as \Deleted, but that starts to become risky).
This would explain why the messages might still exist in the INBOX (although they should be at least marked as deleted).
Not sure why marking a message as deleted is marking it as Seen. That seems like a bug in AE.NET.Mail.

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.

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