将已发送的 MailMessage 放入“已发送文件夹”

Posted

技术标签:

【中文标题】将已发送的 MailMessage 放入“已发送文件夹”【英文标题】:Getting a sent MailMessage into the "Sent Folder" 【发布时间】:2011-01-29 02:20:20 【问题描述】:

我正在使用 Exchange Server 发送带有 SmtpClient 的 MailMessages(已成功发送),但我希望我发送的电子邮件能够转到我发送它们的电子邮件地址的已发送文件夹(未发生)。

using (var mailMessage = new MailMessage("fromaddress@blah.com", "toaddress@blah.com", "subject", "body"))

    var smtpClient = new SmtpClient("SmtpHost")
    
        EnableSsl = false,
        DeliveryMethod = SmtpDeliveryMethod.Network
    ;

    // Apply credentials
    smtpClient.Credentials = new NetworkCredential("smtpUsername", "smtpPassword");

    // Send
    smtpClient.Send(mailMessage);

我是否缺少一个配置来确保我从“fromaddress@blah.com”发送的所有电子邮件都到达他们的发送文件夹?

【问题讨论】:

【参考方案1】:

如果您想将已发送的邮件放在“已发送邮件”文件夹中,您需要从 Outlook 发送邮件。此文件夹是 Outlook(和许多其他邮件客户端)概念,而不是 SMTP 概念。

您可以使用 Outlook 自动化 API 要求 Outlook 创建并发送电子邮件。

【讨论】:

+1 表示“不是 SMTP 概念”。这实际上是问题的症结所在(尽管从 Outlook 发送不太可能适用于 OP)。【参考方案2】:

我猜您的要求主要是为了让用户了解已发送的电子邮件。已发送的项目文件夹将是允许这种情况发生的一种方法。过去,我通过添加BCC Address 解决了这个问题,该BCC Address 可以将电子邮件直接发送到允许用户查看已发送内容的分发列表、用户或共享邮箱。

尝试使用某种 Outlook 规则将项目移动到标记为已读的已发送项目文件夹中...

using (var mailMessage = new MailMessage(
        "fromaddress@blah.com", 
        "toaddress@blah.com", 
        "",
        "fromaddress@blah.com",
        "subject", 
        "body"))

    var smtpClient = new SmtpClient("SmtpHost")
    
        EnableSsl = false,
        DeliveryMethod = SmtpDeliveryMethod.Network
    ;

    // Apply credentials
    smtpClient.Credentials = new NetworkCredential("smtpUsername", "smtpPassword");

    // Send
    smtpClient.Send(mailMessage);

【讨论】:

感谢您的回复!现在这绝对是一个可能的考虑因素,因为它实际上只是我需要的确认...... 下面 LachlanB 的 Exchange 服务答案是真正的答案。这有点小技巧。【参考方案3】:

我已经这样做了,所以为了完整起见,这里是如何正确地做到这一点。使用托管交换网络服务 (http://msdn.microsoft.com/en-us/library/dd633709%28EXCHG.80%29.aspx):

ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);

// In case you have a dodgy SSL certificate:
System.Net.ServicePointManager.ServerCertificateValidationCallback =
            delegate(Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
            
                return true;
            ;

service.Credentials = new WebCredentials("username", "password", "MYDOMAIN");
service.Url = new Uri("https://exchangebox/EWS/Exchange.asmx");

EmailMessage em = new EmailMessage(service);
em.Subject = "example email";
em.Body = new MessageBody("hello world");
em.Sender = new Microsoft.Exchange.WebServices.Data.EmailAddress("john.smith@example.com");
em.ToRecipients.Add(new Microsoft.Exchange.WebServices.Data.EmailAddress("bob.smith@example.com"));

// Send the email and put it into the SentItems:
em.SendAndSaveCopy(WellKnownFolderName.SentItems);

【讨论】:

这应该是最佳答案 @markthewizard1234 - 我相信这个解决方案虽然优雅,但将用户与 Exchange 提供者联系在一起。 OP 目前不受这种限制,因为他们使用的是 SmtpClient。 @OutstandingBill 他提到他正在使用 Exchange,并且无法使用 SmtpClient 来做到这一点【参考方案4】:

我一直在寻找这个问题的答案,但不依赖 Exchange 服务器,而是使用 IMAP 服务器。我不知道这是否超出了问题的范围,但我发现它在搜索“将已发送的 MailMessage 放入已发送的文件夹”,这首先是我的问题。

在我构建自己的解决方案的任何地方都没有找到直接答案:

Simple IMAP CLIENT 在 MSDN 上 Convert MailMessage to Raw text 在 *** 上,这是保存消息的必要步骤。

我将 save 方法作为 smtpClient 的扩展来实现,所以我们将使用 .SendAndSaveMessageToIMAP() 而不是 .Send()

public static class SmtpClientExtensions

    static System.IO.StreamWriter sw = null;
    static System.Net.Sockets.TcpClient tcpc = null;
    static System.Net.Security.SslStream ssl = null;
    static string path;
    static int bytes = -1;
    static byte[] buffer;
    static System.Text.StringBuilder sb = new System.Text.StringBuilder();
    static byte[] dummy;

    /// <summary>
    /// Communication with server
    /// </summary>
    /// <param name="command">The command beeing sent</param>
    private static void SendCommandAndReceiveResponse(string command)
    
        try
        
            if (command != "")
            
                if (tcpc.Connected)
                
                    dummy = System.Text.Encoding.ASCII.GetBytes(command);
                    ssl.Write(dummy, 0, dummy.Length);
                
                else
                
                    throw new System.ApplicationException("TCP CONNECTION DISCONNECTED");
                
            
            ssl.Flush();

            buffer = new byte[2048];
            bytes = ssl.Read(buffer, 0, 2048);
            sb.Append(System.Text.Encoding.ASCII.GetString(buffer));

            sw.WriteLine(sb.ToString());
            sb = new System.Text.StringBuilder();
        
        catch (System.Exception ex)
        
            throw new System.ApplicationException(ex.Message);
        
    

    /// <summary>
    /// Saving a mail message before beeing sent by the SMTP client
    /// </summary>
    /// <param name="self">The caller</param>
    /// <param name="imapServer">The address of the IMAP server</param>
    /// <param name="imapPort">The port of the IMAP server</param>
    /// <param name="userName">The username to log on to the IMAP server</param>
    /// <param name="password">The password to log on to the IMAP server</param>
    /// <param name="sentFolderName">The name of the folder where the message will be saved</param>
    /// <param name="mailMessage">The message being saved</param>
    public static void SendAndSaveMessageToIMAP(this System.Net.Mail.SmtpClient self, System.Net.Mail.MailMessage mailMessage, string imapServer, int imapPort, string userName, string password, string sentFolderName)
    
        try
        
            path = System.Environment.CurrentDirectory + "\\emailresponse.txt";

            if (System.IO.File.Exists(path))
                System.IO.File.Delete(path);

            sw = new System.IO.StreamWriter(System.IO.File.Create(path));

            tcpc = new System.Net.Sockets.TcpClient(imapServer, imapPort);

            ssl = new System.Net.Security.SslStream(tcpc.GetStream());
            ssl.AuthenticateAsClient(imapServer);
            SendCommandAndReceiveResponse("");

            SendCommandAndReceiveResponse(string.Format("$ LOGIN 1 2  0", System.Environment.NewLine, userName, password));

            using (var m = mailMessage.RawMessage())
            
                m.Position = 0;
                var sr = new System.IO.StreamReader(m);
                var myStr = sr.ReadToEnd();
                SendCommandAndReceiveResponse(string.Format("$ APPEND 1 (\\Seen) 20", System.Environment.NewLine, sentFolderName, myStr.Length));
                SendCommandAndReceiveResponse(string.Format("10", System.Environment.NewLine, myStr));
            
            SendCommandAndReceiveResponse(string.Format("$ LOGOUT0", System.Environment.NewLine));
        
        catch (System.Exception ex)
        
            System.Diagnostics.Debug.WriteLine("error: " + ex.Message);
        
        finally
        
            if (sw != null)
            
                sw.Close();
                sw.Dispose();
            
            if (ssl != null)
            
                ssl.Close();
                ssl.Dispose();
            
            if (tcpc != null)
            
                tcpc.Close();
            
        

        self.Send(mailMessage);
    

public static class MailMessageExtensions

    private static readonly System.Reflection.BindingFlags Flags = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic;
    private static readonly System.Type MailWriter = typeof(System.Net.Mail.SmtpClient).Assembly.GetType("System.Net.Mail.MailWriter");
    private static readonly System.Reflection.ConstructorInfo MailWriterConstructor = MailWriter.GetConstructor(Flags, null, new[]  typeof(System.IO.Stream) , null);
    private static readonly System.Reflection.MethodInfo CloseMethod = MailWriter.GetMethod("Close", Flags);
    private static readonly System.Reflection.MethodInfo SendMethod = typeof(System.Net.Mail.MailMessage).GetMethod("Send", Flags);

    /// <summary>
    /// A little hack to determine the number of parameters that we
    /// need to pass to the SaveMethod.
    /// </summary>
    private static readonly bool IsRunningInDotNetFourPointFive = SendMethod.GetParameters().Length == 3;

    /// <summary>
    /// The raw contents of this MailMessage as a MemoryStream.
    /// </summary>
    /// <param name="self">The caller.</param>
    /// <returns>A MemoryStream with the raw contents of this MailMessage.</returns>
    public static System.IO.MemoryStream RawMessage(this System.Net.Mail.MailMessage self)
    
        var result = new System.IO.MemoryStream();
        var mailWriter = MailWriterConstructor.Invoke(new object[]  result );
        SendMethod.Invoke(self, Flags, null, IsRunningInDotNetFourPointFive ? new[]  mailWriter, true, true  : new[]  mailWriter, true , null);
        result = new System.IO.MemoryStream(result.ToArray());
        CloseMethod.Invoke(mailWriter, Flags, null, new object[]  , null);
        return result;
    

所以罗伯特·里德的例子会变成

        using (var mailMessage = new MailMessage("fromaddress@blah.com", "toaddress@blah.com", "subject", "body"))
        
            //Add an attachment just for the sake of it
            Attachment doc = new Attachment(@"filePath");
            doc.ContentId = "doc";
            mailMessage.Attachments.Add(doc);

            var smtpClient = new SmtpClient("SmtpHost")
            
                EnableSsl = false,
                DeliveryMethod = SmtpDeliveryMethod.Network
            ;

            // Apply credentials
            smtpClient.Credentials = new NetworkCredential("smtpUsername", "smtpPassword");

            // Send
            smtpClient.SendAndSaveMessageToIMAP(mailMessage, "imap.mail.com", 993, "imapUsername", "imapPassword", "SENT");
        

【讨论】:

以上是关于将已发送的 MailMessage 放入“已发送文件夹”的主要内容,如果未能解决你的问题,请参考以下文章

使用 MailMessage 向多个收件人发送电子邮件?

使用MailMessage发送邮件

使用 PowerShell V2 的 Send-MailMessage 通过 Gmail 发送邮件

MailMessage 将字符串作为正文发送,在 Outlook 中没有换行符

使用send-mailmessage命令发送域内邮件

将 System.Net.Mail.MailMessage 替换为手动创建的消息并发送