MailKit:邮件客户端显示在移动时收到的消息并且不保留原始标志

MailKit: Mail client is showing message as received at time of move and not retaining original flags

我正在编写一个脚本来将电子邮件从一个帐户迁移到另一个帐户。我有两个问题。

  1. 邮件正在移动,但邮件客户端正在显示他们的 收到日期为 date/time 它被移动(在消息列表中 视图),而不是消息 header 中显示的 date/time。我是 猜测文件日期未被保留?

  2. 消息标志未被复制。比如留言 已经被阅读了。我希望看到所有的标志都被传递...基本上我需要移动消息,因为它存在于以前的帐户中。

    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;
        }
    }
    

您需要使用其他 Append() 方法之一,该方法采用 MessageFlags 参数和 DateTimeOffset 参数来指定消息到达时间的时间戳。

但为了获得该信息,您还需要 Fetch() 每条消息的元数据。

以下是我将如何更改您的循环:

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

固定:

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);
}

和OP一样,我也遇到了同样的问题。我使用了@jstedfast 提供的解决方案,但目标帐户仍然显示具有副本日期和时间的复制电子邮件,而不是原始日期和时间。下面是我的代码。任何建议将不胜感激!

编辑 (12/21/2021):

我找到了这个问题的原因!我最初尝试在不使用保留日期和时间的标志的情况下复制一堆电子邮件。我不知道那是必需的。因此,我随后实施了使用这些标志所必需的更改,并且在再次 运行 程序之前,我删除了我从以前版本的程序复制过来的所有原始电子邮件,但我从未清空 gmail 中的垃圾箱.因此,尽管我再次复制了消息,但它一定只是使用了原始复制的消息并且只是删除了已删除的标志。一旦我再次清空 gmail 垃圾箱和 运行 我的程序,电子邮件就会正确复制,同时保留原始接收日期。

    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;

    }