skip to Main Content

I’m working writing a script to migrate emails from one account to another. I’m having two issues.

  1. The messages are moving over, but the mail client is showing their
    received date as the date/time it was moved (in the list of messages
    view), not the date/time that’s showing in the message header. I’m
    guessing a file date isn’t being retained?

  2. The message flags aren’t being copied over. Such as the message
    being read already. I’d like to see all of the flags being passed…basically I need to move the message as it exists on the previous account.

    protected void CopyBtn_Click(object sender, EventArgs e)
    {
        try
        {
            ImapClient Client = new ImapClient();
            ImapClient Client2 = new ImapClient();
            Client.Connect(SourceHostBox.Text.Trim(), 993, SecureSocketOptions.SslOnConnect);
            Client.Authenticate(SourceUsernameBox.Text.Trim(), SourcePasswordBox.Text.Trim());
            Client.Inbox.Open(FolderAccess.ReadWrite);
            Client2.Connect(DestinationHostBox.Text.Trim(), 993, SecureSocketOptions.SslOnConnect);
            Client2.Authenticate(DestinationUsernameBox.Text.Trim(), DestinationPasswordBox.Text.Trim());
            Client2.Inbox.Open(FolderAccess.ReadWrite);
    
            var folders = Client.GetFolders(Client.PersonalNamespaces[0]);
    
            //move all messages in folders & create folders if necessary
            foreach (var folder in folders)
            {
                folder.Open(FolderAccess.ReadWrite);
                var uids = folder.Search(SearchQuery.All);
    
                foreach (var uid in uids)
                {
                    var folders2 = Client2.GetFolders(Client2.PersonalNamespaces[0]);
                    var message = folder.GetMessage(uid);
                    string currentFolder = folder.ToString().Replace("INBOX.", ""); //Remove the 'INBOX.' text that's getting prepended by cPanel/Dovecot
    
                    var toplevel = Client2.GetFolder(Client2.PersonalNamespaces[0]);
                    var folderExists = FindFolder(toplevel, currentFolder);
                    if (folderExists == null)
                        toplevel.Create(currentFolder, true);
                    Client2.GetFolder(currentFolder).Append(message);
                }
            }
    
            //move inbox messages
            Client.Inbox.Open(FolderAccess.ReadWrite);
            Client2.Inbox.Open(FolderAccess.ReadWrite);
            var inboxuids = Client.Inbox.Search(SearchQuery.All);
            foreach (var uid in inboxuids)
            {
                var message = Client.Inbox.GetMessage(uid);
                Client2.Inbox.Append(message);
            }
    
            label1.Text = "Finished Successfully.";
            label1.ForeColor = System.Drawing.Color.Green;
    
        }
        catch (Exception ex)
        {
            label1.Text = ex.Message;
            label1.ForeColor = System.Drawing.Color.Red;
        }
    }
    

2

Answers


  1. You need to use one of the other Append() methods that takes a MessageFlags argument and a DateTimeOffset argument to specify the timestamp for when the message arrived.

    But in order to get that information, you will also need to Fetch() that metadata for each of the messages.

    Here’s how I would change your loop:

    var inboxuids = Client.Inbox.Search(SearchQuery.All);
    foreach (var uid in inboxuids)
    {
        var message = Client.Inbox.GetMessage(uid);
        Client2.Inbox.Append(message);
    }
    

    Fixed:

    var uids = Client.Inbox.Search (SearchQuery.All);
    var items = Client.Inbox.Fetch (uids, MessageSummaryItems.InternalDate | MessageSummaryItems.Flags);
    foreach (var item in items)
    {
        var message = Client.Inbox.GetMessage (item.UniqueId);
    
        Client2.Inbox.Append (message, item.Flags.Value, item.InternalDate.Value);
    }
    
    Login or Signup to reply.
  2. Like the OP, I am having the same issue. I used the solution provided by @jstedfast but the destination account still shows the copied email having the date and time of the copy and not the original date and time. Below is my code. Any suggestions would be greatly appreciated!

    Edit (12/21/2021):

    I figured out the cause of this issue! I had initially tried copying over a bunch of emails without using the flags that retains the date and time. I didn’t know that would be required. So I then implemented the changes necessary to use those flags and before running the program again, I deleted all of the original emails that I had copied over from the previous version of my program, but I never emptied the trash in gmail. So although I was copying over the messages again, it must have just used the original copied messages and just removed the deleted flag. Once I emptied the gmail trash and ran my program again, the emails copied over correctly while retaining the original received date.

        private void CopyEmailsAndFolders()
        {
            try
            {  
                ImapClient yahooEmailAccnt = connectToEmailServerAndAccount(SrcEmailAccount.ImapServer, SrcEmailAccount.LogFileName, SrcEmailAccount.AccountUserName, SrcEmailAccount.AccountPassword);
                ImapClient gmailEmailAccnt = connectToEmailServerAndAccount(DestEmailAccount.ImapServer, DestEmailAccount.LogFileName, DestEmailAccount.AccountUserName, DestEmailAccount.AccountPassword);
    
                try
                {
                    List<string> yahooFoldersList = getFoldersList(yahooEmailAccnt);                
                
                    //loop through each of the folders in the source (Yahoo) email account
                    foreach (string folderName in yahooFoldersList)
                    {
                        if (folderName.ToLower() == "inbox")
                        {
                            continue;
                        }
    
                        var gmailFolder = gmailEmailAccnt.GetFolder(folderName);
                        var yahooFolder = yahooEmailAccnt.GetFolder(folderName);
    
                        yahooFolder.Open(FolderAccess.ReadOnly);
    
                        //get a list of all email UID's
                        var uids = yahooFolder.Search(SearchQuery.All);
                        
                        //now get a list of all the items in the folder to include the critical date time properties we want to preserve
                        var items = yahooFolder.Fetch(uids, MessageSummaryItems.InternalDate | MessageSummaryItems.Flags);
    
                        //now loop through all of the emails we found in the current folder and copy them to the destination (gmail) email account
                        foreach (var item in items)
                        {
                            var message = yahooFolder.GetMessage(item.UniqueId);
                            gmailFolder.Append(message, item.Flags.Value, item.InternalDate.Value);
                        }
                    }
                }
                catch (Exception fEx)
                {
                    MessageBox.Show(fEx.Message);
                }
                finally
                {
                    yahooEmailAccnt.Disconnect(true);
                    gmailEmailAccnt.Disconnect(true);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
    
        }
    
        private ImapClient connectToEmailServerAndAccount(string imapServer, string logFile, string userName, string password)
        {
            ImapClient newEmailClient = new ImapClient();
            
            try
            {
                newEmailClient = new ImapClient(new ProtocolLogger(logFile));
                newEmailClient.Connect(imapServer, 993, SecureSocketOptions.SslOnConnect);
                newEmailClient.Authenticate(userName, password);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
    
            return newEmailClient;
        }
    
        private List<string> getFoldersList(ImapClient emailClient)
        {
            List<string> foldersList = new List<string>();
            
            try
            {
                // Get the first personal namespace and list the toplevel folders under it.
                var personal = emailClient.GetFolder(emailClient.PersonalNamespaces[0]);
    
                foreach (var folder in personal.GetSubfolders(false))
                {
                    foldersList.Add(folder.Name);
                    Console.WriteLine("[folder] {0}", folder.Name);
                }                
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
    
            return foldersList;
    
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search