使用 SMTP 客户端在 C# 中发送电子邮件、转发消息并执行邮件合并

发送电子邮件

使用 SmtpClient 类发送电子邮件

SmtpClient 类使应用程序能够通过简单邮件传输协议 (SMTP) 发送电子邮件。

其关键特性之一是能够 批量发送消息.

它也完全支持 同步异步 编程模型。若要在操作完成前阻塞主线程发送电子邮件,开发者可以使用同步的 发送 方法。此外,为了在发送邮件时让主线程继续执行,开发者可以使用 SendAsync 方法。

此外, SmtpClient 支持发送消息的 传输中立封装格式 (TNEF).

同步发送电子邮件

可以使用…同步发送电子邮件 发送 方法的 SmtpClient 类。它通过 SMTP 服务器发送指定的电子邮件以进行投递。要同步发送电子邮件,请按以下步骤进行:

  1. 创建以下实例: MailMessage 类并设置其属性。
  2. 创建以下实例: SmtpClient 类并指定主机、端口、用户名和密码。
  3. 使用…发送消息 发送 方法的 SmtpClient 类并传递 MailMessage 实例。

以下 C# 代码片段展示了如何同步发送 Outlook 邮件。

// For complete examples and data files, please go to https://github.com/aspose-email/Aspose.Email-for-.NET
// Declare msg as MailMessage instance
MailMessage msg = new MailMessage();

// Create an instance of SmtpClient class
SmtpClient client = new SmtpClient();

// Specify your mailing host server, Username, Password, Port # and Security option
client.Host = "mail.server.com";
client.Username = "username";
client.Password = "password";
client.Port = 587;
client.SecurityOptions = SecurityOptions.SSLExplicit;

try
{
    // Client.Send will send this message
    client.Send(msg);
    Console.WriteLine("Message sent");
}
catch (Exception ex)
{
    Trace.WriteLine(ex.ToString());
}

异步发送电子邮件

有时,您可能希望异步发送邮件,以便程序在后台发送邮件时继续执行其他操作。从 .NET Framework 4.5 开始,您可以使用符合以下实现的异步方法 TAP 模型。下面的 C# 代码片段展示了如何使用基于任务的异步模式方法发送 Outlook 电子邮件。

  • SendAsync 发送指定的消息。

  • IAsyncSmtpClient - 允许应用程序使用 Simple Mail Transfer Protocol(SMTP)发送消息。

  • SmtpClient.CreateAsync - 创建 Aspose.Email.Clients.Smtp.SmtpClient 类的新实例

  • SmtpSend - Aspose.Email.Clients.Smtp.IAsyncSmtpClient.SendAsync(Aspose.Email.Clients.Smtp.Models.SmtpSend) 方法的参数集合。

  • SmtpForward - Aspose.Email.Clients.Smtp.IAsyncSmtpClient.ForwardAsync(Aspose.Email.Clients.Smtp.Models.SmtpForward) 参数。

// Authenticate the client to obtain necessary permissions
static readonly string tenantId = "YOU_TENANT_ID";
static readonly string clientId = "YOU_CLIENT_ID";
static readonly string redirectUri = "http://localhost";
static readonly string username = "username";
static readonly string[] scopes = { "https://outlook.office.com/SMTP.Send" };

// Use the SmtpAsync method for asynchronous operations
static async Task Main(string[] args)
{
    await SmtpAsync();
    Console.ReadLine();
}

static async Task SmtpAsync()
{
    // Create token provider and get access token
    var tokenProvider = new TokenProvider(clientId, tenantId, redirectUri, scopes);
    var client = SmtpClient.CreateAsync("outlook.office365.com", username, tokenProvider, 587).GetAwaiter().GetResult();

    // Create a message to send
    var eml = new MailMessage("from@domain.com", "to@domain.com", "test subj async", "test body async");
    
    // send message
    var sendOptions = SmtpSend.Create();
    sendOptions.AddMessage(eml);
    await client.SendAsync(sendOptions);
    Console.WriteLine("message was sent");

    // forward message
    var fwdOptions = SmtpForward.Create();
    fwdOptions.SetMessage(eml);
    fwdOptions.AddRecipient("rec@domain.com");
    await client.ForwardAsync(fwdOptions);
    Console.WriteLine("message was forwarded");
}

// Token provider implementation
public class TokenProvider : IAsyncTokenProvider
{
    private readonly PublicClientApplicationOptions _pcaOptions;
    private readonly string[] _scopes;

    public TokenProvider(string clientId, string tenantId, string redirectUri, string[] scopes)
    {
        _pcaOptions = new PublicClientApplicationOptions
        {
            ClientId = clientId,
            TenantId = tenantId,
            RedirectUri = redirectUri
        };

        _scopes = scopes;
    }

    public async Task<OAuthToken> GetAccessTokenAsync(bool ignoreExistingToken = false, CancellationToken cancellationToken = default)
    {

        var pca = PublicClientApplicationBuilder
            .CreateWithApplicationOptions(_pcaOptions).Build();

        try
        {
            var result = await pca.AcquireTokenInteractive(_scopes)
                .WithUseEmbeddedWebView(false)
                .ExecuteAsync(cancellationToken);

            return new OAuthToken(result.AccessToken);
        }
        catch (MsalException ex)
        {
            Console.WriteLine($"Error acquiring access token: {ex}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex}");
        }

        return null;
    }

    public void Dispose()
    {

    }
}

从磁盘发送消息

EML 文件包含头部、正文和附件。Aspose.Email 让开发者以多种方式处理 EML 文件。本节展示了如何从磁盘加载 EML 文件并通过 SMTP 发送为电子邮件。您可以将 .eml 文件从磁盘或流加载到 MailMessage 类并使用 SmtpClient 类。该 MailMessage 类是用于创建新电子邮件、从磁盘或流加载电子邮件文件以及保存消息的主要类。以下 C# 代码片段展示了如何从磁盘发送已存储的消息。

// For complete examples and data files, please go to https://github.com/aspose-email/Aspose.Email-for-.NET
// Load an EML file in MailMessage class
var message = MailMessage.Load(dataDir + "test.eml");

// Send this message using SmtpClient
var client = new SmtpClient("host", "username", "password");
            
try
{
    client.Send(message);
}
catch (Exception ex)
{
    Console.WriteLine(ex.Message);
}            

发送纯文本电子邮件

正文 属性,是 MailMessage 类用于指定消息正文的纯文本内容。要发送纯文本电子邮件,请按以下步骤操作:

以下代码片段展示了如何发送纯文本电子邮件。

// For complete examples and data files, please go to https://github.com/aspose-email/Aspose.Email-for-.NET
//Create an instance of the MailMessage class
var message = new MailMessage();

// Set From field, To field and Plain text body
message.From = "sender@sender.com";
message.To.Add("receiver@receiver.com");
message.Body = "This is Plain Text Body";

// Create an instance of the SmtpClient class
var client = new SmtpClient();

// And Specify your mailing host server, Username, Password and Port
client.Host = "smtp.server.com";
client.Username = "Username";
client.Password = "Password";
client.Port = 25;

try
{
    //Client.Send will send this message
    client.Send(message);
    Console.WriteLine("Message sent");
}
catch (Exception ex)
{
    System.Diagnostics.Trace.WriteLine(ex.ToString());
}

发送带 HTML 正文的电子邮件

下面的编程示例展示了如何发送简易的 HTML 邮件。该 HtmlBody,是 MailMessage 类用于指定消息正文的 HTML 内容。要发送简易的 HTML 邮件,请按以下步骤操作:

本文中,电子邮件的 HTML 内容为简易示例:This is the HTML body 大多数 HTML 邮件会更复杂。以下代码片段演示了如何发送带有 HTML 正文的电子邮件。

// For complete examples and data files, please go to https://github.com/aspose-email/Aspose.Email-for-.NET
public static void Run()
{
    // Declare msg as MailMessage instance
    var msg = new MailMessage();

    // Use MailMessage properties like specify sender, recipient, message and HtmlBody
    msg.From = "newcustomeronnet@gmail.com";
    msg.To = "asposetest123@gmail.com";
    msg.Subject = "Test subject";
    msg.HtmlBody = "<html><body>This is the HTML body</body></html>";

    var client = GetSmtpClient();

    try
    {
        // Client will send this message
        client.Send(msg);
        Console.WriteLine("Message sent");
    }
    catch (Exception ex)
    {
        Trace.WriteLine(ex.ToString());
    }

    Console.WriteLine(Environment.NewLine + "Email sent with HTML body.");
}

private static SmtpClient GetSmtpClient()
{
    var client = new SmtpClient("smtp.gmail.com", 587, "your.email@gmail.com", "your.password");
    client.SecurityOptions = SecurityOptions.Auto;
    return client;
}

发送带备用文本的 HTML 电子邮件

使用 AlternateView 类中指定电子邮件消息的不同格式副本。例如,如果您以 HTML 发送消息,可能还希望为无法显示 HTML 内容的收件人提供纯文本版本。或者在发送简报时,您可能想为选择接收纯文本版本的收件人提供纯文本副本。要发送包含替代文本的电子邮件,请按以下步骤操作:

  1. 创建该类的实例 MailMessage 类。
  2. MailMessage 实例。
  3. 创建该类的实例 AlternateView 类。

这会使用字符串中指定的内容为电子邮件消息创建替代视图。

  1. 添加该类的实例 AlternateView 类发送到 MailMessage 对象。
  2. 创建该类的实例 SmtpClient 类并使用 发送 方法。

以下代码片段展示了如何发送包含替代文本的电子邮件。

// For complete examples and data files, please go to https://github.com/aspose-email/Aspose.Email-for-.NET
// Declare message as MailMessage instance
var message = new MailMessage();

// Creates AlternateView to view an email message using the content specified in the //string
var alternate = AlternateView.CreateAlternateViewFromString("Alternate Text");
            
// Adding alternate text
message.AlternateViews.Add(alternate);

批量发送电子邮件

我们可以使用该方法发送一批电子邮件 SmtpClient 类的 发送 接受 MailMessageCollection:

  1. 创建以下实例: SmtpClient 类。
  2. 指定 SmtpClient 类属性。
  3. 创建该类的实例 MailMessage 类。
  4. 在实例中指定发件人、收件人、邮件主题和内容 MailMessage 类。
  5. 如果想给其他人发送邮件,请再次重复以上两步。
  6. 创建以下实例: MailMessageCollection 类。
  7. 添加一个实例 MailMessage 类在对象的 MailMessageCollection 类。
  8. 现在使用 SmtpClient发送 方法通过传入 MailMessageCollection 其中的类。

以下代码片段展示了如何批量发送电子邮件。

// For complete examples and data files, please go to https://github.com/aspose-email/Aspose.Email-for-.NET
// Create SmtpClient as client and specify server, port, user name and password
var client = new SmtpClient("mail.server.com", 25, "Username", "Password");

// Create instances of MailMessage class and Specify To, From, Subject and Message
var message1 = new MailMessage("msg1@from.com", "msg1@to.com", "Subject1", "message1, how are you?");
var message2 = new MailMessage("msg1@from.com", "msg2@to.com", "Subject2", "message2, how are you?");
var message3 = new MailMessage("msg1@from.com", "msg3@to.com", "Subject3", "message3, how are you?");

// Create an instance of MailMessageCollection class
var manyMsg = new MailMessageCollection();
manyMsg.Add(message1);
manyMsg.Add(message2);
manyMsg.Add(message3);

try
{
    // Send Messages using Send method
    client.Send(manyMsg);                
    Console.WriteLine("Message sent");
}
catch (Exception ex)
{
    Trace.WriteLine(ex.ToString());
}

跟踪批量邮件发送成功

批量发送消息时,您可以获取已成功发送的消息数量信息,甚至获取这些消息的列表。 SucceededSending 事件用于此目的。

代码示例:

using (var client = new SmtpClient(host, SecurityOptions.Auto))
{
    int messageCount = 0;

    client.SucceededSending += (sender, eventArgs) =>
    {
        Console.WriteLine("The message '{0}' was successfully sent.", eventArgs.Message.Subject);
        messageCount++;
    };

    client.Send(messages);

    Console.WriteLine("{0} messages were successfully sent.", messageCount);
}

使用多连接发送电子邮件

该 UseMultiConnection 属性可用于为繁重操作创建多个连接。您还可以通过使用该属性设置多连接模式下使用的连接数。 SmtpClient.ConnectionsQuantity。以下代码片段演示了使用多连接模式发送多条消息。

var smtpClient = new SmtpClient();
smtpClient.Host = "<HOST>";
smtpClient.Username = "<USERNAME>";
smtpClient.Password = "<PASSWORD>";
smtpClient.Port = 587;
smtpClient.SupportedEncryption = EncryptionProtocols.Tls;
smtpClient.SecurityOptions = SecurityOptions.SSLExplicit;

var messages = new List<MailMessage>();
for (int i = 0; i < 20; i++)
{
    MailMessage message = new MailMessage(
        "<EMAIL ADDRESS>",
        "<EMAIL ADDRESS>",
        "Test Message - " + Guid.NewGuid().ToString(),
        "SMTP Send Messages with MultiConnection");
    messages.Add(message);
}

smtpClient.ConnectionsQuantity = 5;
smtpClient.UseMultiConnection = MultiConnectionMode.Enable;
smtpClient.Send(messages);

以 TNEF 形式发送邮件

TNEF 邮件拥有特殊的格式,如果使用标准 API 发送可能会丢失。 SmtpClient 类 UseTnef 属性可以设置为以 TNEF 形式发送电子邮件。以下代码片段展示了如何以 TNEF 发送消息。

var emlFileName = RunExamples.GetDataDir_Email() + "Message.eml";     // A TNEF Email

// Load from eml
var eml1 = MailMessage.Load(emlFileName, new EmlLoadOptions());
eml1.From = "somename@gmail.com";
eml1.To.Clear();
eml1.To.Add(new MailAddress("first.last@test.com"));
eml1.Subject = "With PreserveTnef flag during loading";
eml1.Date = DateTime.Now;

var client = new SmtpClient("smtp.gmail.com", 587, "somename", "password");
client.SecurityOptions = SecurityOptions.Auto;
client.UseTnef = true;     // Use this flag to send as TNEF
client.Send(eml1);

发送会议请求

Aspose.Email 让开发者能够在电子邮件中添加日历功能。

通过电子邮件发送请求

要通过电子邮件发送会议请求,请按以下步骤操作:

|iCalendar 会议请求通过电子邮件发送| | :- | |todo:image_alt_text| 以下代码片段展示了如何通过电子邮件发送请求。


// Create an instance of the MailMessage class
var msg = new MailMessage();

// Set the sender, recipient, who will receive the meeting request. Basically, the recipient is the same as the meeting attendees
msg.From = "newcustomeronnet@gmail.com";
msg.To = "person1@domain.com, person2@domain.com, person3@domain.com, asposetest123@gmail.com";

// Create Appointment instance
var app = new Appointment("Room 112", new DateTime(2015, 7, 17, 13, 0, 0), new DateTime(2015, 7, 17, 14, 0, 0), msg.From, msg.To);
app.Summary = "Release Meetting";
app.Description = "Discuss for the next release";

// Add appointment to the message and Create an instance of SmtpClient class
msg.AddAlternateView(app.RequestApointment());
var client = GetSmtpClient();

try
{
    // Client.Send will send this message
    client.Send(msg);
    Console.WriteLine("Message sent");
}
catch (Exception ex)
{
    Trace.WriteLine(ex.ToString());
}

转发邮件

使用 SMTP 客户端转发邮件

转发电子邮件是常见做法。收到的邮件可以转发给特定收件人。 转发 此方法可用于将已接收或已保存的电子邮件转发给指定收件人。以下代码片段演示了如何使用 SMTP 客户端转发电子邮件。

//Create an instance of SmtpClient class
var client = new SmtpClient();

// Specify your mailing host server, Username, Password, Port and SecurityOptions
client.Host = "mail.server.com";
client.Username = "username";
client.Password = "password";
client.Port = 587;
client.SecurityOptions = SecurityOptions.SSLExplicit;
var message = MailMessage.Load(dataDir + "Message.eml");
client.Forward("Recipient1@domain.com", "Recipient2@domain.com", message);

在不使用 MailMessage 转发邮件

该 API 还支持在未先加载到 MailMessage。这在系统内存资源有限的情况下很有用。


using (var client = new SmtpClient(host, smtpPort, username, password, SecurityOptions.Auto))
{
    using (var fs = File.OpenRead(@"test.eml"))
    {
        client.Forward(sender, recipients, fs);
    }
}

在不使用 MailMessage 的情况下异步转发邮件

using (var client = new SmtpClient(host, smtpPort, username, password))
{
    using (var fs = File.OpenRead(@"test.eml"))
    {
        await client.ForwardAsync(sender, recipients, fs);
    }
}

邮件合并

如何合并电子邮件

邮件合并帮助您创建并发送一批相似的电子邮件。邮件的核心内容相同,但可以对内容进行个性化。通常使用收件人的联系信息(名、姓、公司等)来个性化邮件。

|邮件合并工作示意:| | :- | |todo:image_alt_text| Aspose.Email 让开发者能够设置包含多种数据源数据的邮件合并。

要使用 Aspose.Email 执行邮件合并,请执行以下步骤:

  1. 创建一个具有以下签名的函数
  2. 创建该类的实例 MailMessage 类。
  3. 指定发件人、收件人、主题和正文。
  4. 为电子邮件末尾创建签名。
  5. 创建该类的实例 TemplateEngine 类中获取签名并传递给 MailMessage 实例。
  6. TemplateEngine 实例。
  7. 创建 DataTable 类的实例。
  8. 在 DataTable 类中添加列 ReceiptFirstNameLastName 作为数据源。
  9. 创建 DataRow 类的实例。
  10. 在 DataRow 对象中指定收件地址、名和姓。
  11. 创建该类的实例 MailMessageCollection 类
  12. 指定 TemplateEngine  以及 DataTable 实例在 MailMessageCollection 实例。
  13. 创建该类的实例 SmtpClient 类并指定服务器、端口、用户名和密码。
  14. 使用以下方式发送电子邮件: SmtpClient 类 发送 方法。

在下面的示例中,#FirstName# 表示 DataTable 列,其值由用户设置。以下代码片段演示了如何执行邮件合并。

// For complete examples and data files, please go to https://github.com/aspose-email/Aspose.Email-for-.NET
public static void Run()
{
    // The path to the File directory.
    string dataDir = RunExamples.GetDataDir_SMTP();
    string dstEmail = dataDir + "EmbeddedImage.msg";

    // Create a new MailMessage instance
    MailMessage msg = new MailMessage();

    // Add subject and from address
    msg.Subject = "Hello, #FirstName#";
    msg.From = "sender@sender.com";

    // Add email address to send email also Add mesage field to HTML body
    msg.To.Add("your.email@gmail.com");
    msg.HtmlBody = "Your message here";
    msg.HtmlBody += "Thank you for your interest in <STRONG>Aspose.Email</STRONG>.";

    // Use GetSignment as the template routine, which will provide the same signature
    msg.HtmlBody += "<br><br>Have fun with it.<br><br>#GetSignature()#";

    // Create a new TemplateEngine with the MSG message,  Register GetSignature routine. It will be used in MSG.
    TemplateEngine engine = new TemplateEngine(msg);
    engine.RegisterRoutine("GetSignature", GetSignature);

    // Create an instance of DataTable and Fill a DataTable as data source
    DataTable dt = new DataTable();
    dt.Columns.Add("Receipt", typeof(string));
    dt.Columns.Add("FirstName", typeof(string));
    dt.Columns.Add("LastName", typeof(string));

    DataRow dr = dt.NewRow();
    dr["Receipt"] = "abc<asposetest123@gmail.com>";
    dr["FirstName"] = "a";
    dr["LastName"] = "bc";
    dt.Rows.Add(dr);
    dr = dt.NewRow();
    dr["Receipt"] = "John<email.2@gmail.com>";
    dr["FirstName"] = "John";
    dr["LastName"] = "Doe";
    dt.Rows.Add(dr);
    dr = dt.NewRow();
    dr["Receipt"] = "Third Recipient<email.3@gmail.com>";
    dr["FirstName"] = "Third";
    dr["LastName"] = "Recipient";
    dt.Rows.Add(dr);

    MailMessageCollection messages;
    try
    {
        // Create messages from the message and datasource.
        messages = engine.Instantiate(dt);

        // Create an instance of SmtpClient and specify server, port, username and password
        SmtpClient client = new SmtpClient("smtp.gmail.com", 587, "your.email@gmail.com", "your.password");
        client.SecurityOptions = SecurityOptions.Auto;

        // Send messages in bulk
        client.Send(messages);
    }
    catch (MailException ex)
    {
        Debug.WriteLine(ex.ToString());
    }

    catch (SmtpException ex)
    {
        Debug.WriteLine(ex.ToString());
    }

    Console.WriteLine(Environment.NewLine + "Message sent after performing mail merge.");
}

// Template routine to provide signature
static object GetSignature(object[] args)
{
    return "Aspose.Email Team<br>Aspose Ltd.<br>" + DateTime.Now.ToShortDateString();
}

如何执行行级邮件合并

用户可以合并单个数据行,也可以获取完整且已准备好的 MailMessage 对象。该 TemplateEngine.Merge 方法可用于执行逐行邮件合并。

// For complete examples and data files, please go to https://github.com/aspose-email/Aspose.Email-for-.NET
// Create message from the data in current row.
message = engine.Merge(currentRow);