使用C#发送电子邮件

67

我需要通过我的C#应用程序发送电子邮件。

我来自VB 6背景,并且曾经有许多与MAPI控件相关的不良经历。 首先,MAPI不支持HTML电子邮件;其次,所有电子邮件都被发送到默认的发件箱。所以我仍然需要点击“发送/接收”按钮。

如果我需要发送大量的HTML格式邮件(100-200封),在C#中最好的方法是什么?

15个回答

95
你可以使用.NET框架的System.Net.Mail.MailMessage类。
您可以在MSDN文档中找到它。
这是一个简单的示例(代码片段):
using System.Net;
using System.Net.Mail;
using System.Net.Mime;

...
try
{

   SmtpClient mySmtpClient = new SmtpClient("my.smtp.exampleserver.net");

    // set smtp-client with basicAuthentication
    mySmtpClient.UseDefaultCredentials = false;
   System.Net.NetworkCredential basicAuthenticationInfo = new
      System.Net.NetworkCredential("username", "password");
   mySmtpClient.Credentials = basicAuthenticationInfo;

   // add from,to mailaddresses
   MailAddress from = new MailAddress("test@example.com", "TestFromName");
   MailAddress to = new MailAddress("test2@example.com", "TestToName");
   MailMessage myMail = new System.Net.Mail.MailMessage(from, to);

   // add ReplyTo
   MailAddress replyTo = new MailAddress("reply@example.com");
   myMail.ReplyToList.Add(replyTo);

   // set subject and encoding
   myMail.Subject = "Test message";
   myMail.SubjectEncoding = System.Text.Encoding.UTF8;

   // set body-message and encoding
   myMail.Body = "<b>Test Mail</b><br>using <b>HTML</b>.";
   myMail.BodyEncoding = System.Text.Encoding.UTF8;
   // text or html
   myMail.IsBodyHtml = true;

   mySmtpClient.Send(myMail);
}

catch (SmtpException ex)
{
  throw new ApplicationException
    ("SmtpException has occured: " + ex.Message);
}
catch (Exception ex)
{
   throw ex;
}

2
在将密码直接嵌入代码中的方法之外,是否有其他替代方案? - Gabe Sumner
7
NetworkCredential类是重载的。如果提供一个空的构造函数,它将使用当前用户创建实例。或者,您也可以加密用户名和密码并将其存储在外部。这也取决于您如何设置邮件服务器。您可以在本地主机上设置SMTP服务器,并允许它成为环回地址的中继,以便您可以发送不需要凭据的电子邮件。我们采用后一种方法。它很轻量级,简单,并且不需要存储密码(因为任何人都可以从环回地址进行中继 - 这意味着IIS也可以)。 - Joseph Ferris
4
你可以在配置文件中使用 <system.net><mailSettings> 来设置所有这些内容。我经常用它来将邮件发送到一个目录,以便在开发过程中进行测试,然后在准备上线时切换为实际发送邮件。请注意,不要改变原文的意思。 - dotjoe
1
replyTo 属性已被弃用,现在您必须使用 myMail.ReplyToList.Add(replyTo);,它允许多个回复地址。如果您像这样设置了属性,则还可以使用 ConfigurationManager.appSettings["replyTo"] 从配置文件中提取属性:<configuration> <appSettings> <add key="replyTo" value="reply@example.com"/> </appSettings> </configuration> - CSS
2
来自MSDN的重要提示:<br/>
  • SmtpClient类没有Finalize方法,因此应用程序必须调用Dispose来显式释放资源。
  • SmtpClient类型现已过时。我们不建议您在新开发中使用SmtpClient类,因为SmtpClient不支持许多现代协议。
- Stefan Illner

15

代码:

using System.Net.Mail

new SmtpClient("smtp.server.com", 25).send("from@email.com", 
                                           "to@email.com", 
                                           "subject", 
                                           "body");

大量邮件:

SMTP服务器通常有一次处理连接数的限制,如果尝试发送大量邮件,则应用程序可能会出现无响应的情况。

解决方案:

  • 如果正在构建 WinForm,则使用 BackgroundWorker 处理队列。
  • 如果正在使用 IIS SMTP 服务器或具有 outbox 文件夹的 SMTP 服务器,则可以使用 SmtpClient().PickupDirectoryLocation = "c:/smtp/outboxFolder"; 这将保持系统响应。
  • 如果没有使用本地 SMTP 服务器,则可以构建一个系统服务来使用 Filewatcher 监视一个文件夹,然后处理放置在其中的任何电子邮件。

3
对于我的简单需求,你的答案很好用。只需要两行代码,而不是20行! - MrVimes

15

发送批量邮件的最快方法是使用线程。我编写了这个控制台应用程序来发送批量邮件。我通过创建两个线程池将批量电子邮件 ID 分为两个批次。

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Mail;

namespace ConsoleApplication1
{
    public class SendMail 
    {
        string[] NameArray = new string[10] { "Recipient 1", 
                                              "Recipient 2",
                                              "Recipient 3",
                                              "Recipient 4", 
                                              "Recipient 5", 
                                              "Recipient 6", 
                                              "Recipient 7", 
                                              "Recipient 8",
                                              "Recipient 9",
                                              "Recipient 10"
                                            };        

        public SendMail(int i, ManualResetEvent doneEvent)
        {
            Console.WriteLine("Started sending mail process for {0} - ", NameArray[i].ToString() + " at " + System.DateTime.Now.ToString());
            Console.WriteLine("");
            SmtpClient mailClient = new SmtpClient();
            mailClient.Host = Your host name;
            mailClient.UseDefaultCredentials = true;
            mailClient.Port = Your mail server port number; // try with default port no.25

            MailMessage mailMessage = new MailMessage(FromAddress,ToAddress);//replace the address value
            mailMessage.Subject = "Testing Bulk mail application";
            mailMessage.Body = NameArray[i].ToString();
            mailMessage.IsBodyHtml = true;
            mailClient.Send(mailMessage);
            Console.WriteLine("Mail Sent succesfully for {0} - ",NameArray[i].ToString() + " at " + System.DateTime.Now.ToString());
            Console.WriteLine("");

            _doneEvent = doneEvent;
        }

        public void ThreadPoolCallback(Object threadContext)
        {
            int threadIndex = (int)threadContext;
            Console.WriteLine("Thread process completed for {0} ...",threadIndex.ToString() + "at" +  System.DateTime.Now.ToString());
            _doneEvent.Set();
        }      

        private ManualResetEvent _doneEvent;
    }


    public class Program
    {
        static int TotalMailCount, Mailcount, AddCount, Counter, i, AssignI;  
        static void Main(string[] args)
        {
            TotalMailCount = 10;
            Mailcount = TotalMailCount / 2;
            AddCount = Mailcount;
            InitiateThreads();                     

            Thread.Sleep(100000);
        }

       static void InitiateThreads()
       {
            //One event is used for sending mails for each person email id as batch
           ManualResetEvent[] doneEvents = new ManualResetEvent[Mailcount];

            // Configure and launch threads using ThreadPool:
            Console.WriteLine("Launching thread Pool tasks...");

            for (i = AssignI; i < Mailcount; i++)            
            {
                doneEvents[i] = new ManualResetEvent(false);
                SendMail SRM_mail = new SendMail(i, doneEvents[i]);
                ThreadPool.QueueUserWorkItem(SRM_mail.ThreadPoolCallback, i);
            }

            Thread.Sleep(10000);

            // Wait for all threads in pool to calculation...
            //try
            //{
            // //   WaitHandle.WaitAll(doneEvents);
            //}
            //catch(Exception e)
            //{
            //    Console.WriteLine(e.ToString());   
            //}

            Console.WriteLine("All mails are sent in this thread pool.");
            Counter = Counter+1;
            Console.WriteLine("Please wait while we check for the next thread pool queue");
            Thread.Sleep(5000);
            CheckBatchMailProcess();            
        }

        static  void CheckBatchMailProcess()
        {

            if (Counter < 2)
            {
                Mailcount = Mailcount + AddCount;
                AssignI = Mailcount - AddCount;
                Console.WriteLine("Starting the Next thread Pool");

                Thread.Sleep(5000);
                InitiateThreads();
            }

            else
            {
                Console.WriteLine("No thread pools to start - exiting the batch mail application");
                Thread.Sleep(1000);
                Environment.Exit(0);
            }
        }
    }   
}

我在数组列表中定义了10个收件人样本。它将创建两批电子邮件以创建两个线程池来发送邮件。您也可以从数据库中获取详细信息。

您可以通过将此代码复制并粘贴到控制台应用程序中(替换program.cs文件)来使用此代码。然后该应用程序就可以使用了。

希望这可以帮助您 :).


5

2023年4月更新:

现在推荐使用的库是{{link1:Mailkit}}。

using MailKit.Net.Smtp;
using MimeKit;

var message = new MimeMessage();
message.From.Add(new MailboxAddress(name: "John Doe", address: "joe@inbox.test"));
message.To.Add(new MailboxAddress(name: "Bruce Williams", address: "bruce@inbox.test"));
message.Subject = "Test subject";

message.Body = new TextPart("plain")
{
    Text = "Test body"
};

using (var client = new SmtpClient())
{
    client.Connect(host: "mail.inbox.example", port: 587, useSsl: true);
    client.Authenticate(userName: "test", password: "test");
    client.Send(message);
    client.Disconnect(quit: true);
}

System.Net.Mail.SmtpClient不被.NET作者推荐

MailKit的作者也说:

对于SMTP,大多数开发者使用System.Net.Mail.SmtpClient,它基本可以满足他们的需求,因此可能不是他们需求列表中的首选。然而,MailKit中包含的SmtpClient实现是一个更好的选择,如果需要跨平台支持,或者开发者想要能够在通过SMTP发送之前保存和重新加载MIME消息。MailKit的SmtpClient还支持PIPELINING,这应该会提高发送消息的性能(尽管可能不会非常明显)。


4
.NET框架具有一些内置类,允许您通过应用程序发送电子邮件。您应该查看System.Net.Mail命名空间,在那里您将找到MailMessage和SmtpClient类。您可以将MailMessage类的BodyFormat设置为MailFormat.Html。如果您使用MailMessage类的AlternateViews属性,则还可以提供电子邮件的纯文本版本,以便可以读取不支持HTML的客户端。

http://msdn.microsoft.com/en-us/library/system.net.mail.mailmessage.alternateviews.aspx


答案的顺序是如何定义的?一段时间前,splattne的答案是第三个,现在是第一个... 我想我应该阅读FAQ ;)(第一次来这里) - Frederik Gheysels
首先是被接受的答案,其次是按投票排名的其他答案。 - edosoft

4
您可以使用SMTP或CDO发送电子邮件。 使用SMTP:
mail.From = new MailAddress("your_email_address@gmail.com");
mail.To.Add("to_address");
mail.Subject = "Test Mail";
mail.Body = "This is for testing SMTP mail from GMAIL";

SmtpServer.Port = 587;
SmtpServer.Credentials = new System.Net.NetworkCredential("username", "password");
SmtpServer.EnableSsl = true;

using CDO

CDO.Message oMsg = new CDO.Message();
CDO.IConfiguration iConfg;
iConfg = oMsg.Configuration;
ADODB.Fields oFields;
oFields = iConfg.Fields;
ADODB.Field oField = oFields["http://schemas.microsoft.com/cdo/configuration/sendusing"];
oFields.Update();
oMsg.Subject = "Test CDO";
oMsg.From = "from_address";
oMsg.To = "to_address";
oMsg.TextBody = "CDO Mail test";
oMsg.Send();

来源: C# SMTP邮件

来源: C# CDO邮件


2
   public string sendEmail(string mail,string subject, string body)
   {
       try
       {
           MailMessage message = new MailMessage();
           SmtpClient smtp = new SmtpClient();
           message.From = new MailAddress("example@gmail.com");
           message.To.Add(new MailAddress(mail));
           message.Subject = subject;
           message.IsBodyHtml = true; //to make message body as html  
           message.Body = body;
           smtp.Port = 587;
           smtp.Host = "smtp.gmail.com"; //for gmail host  
           smtp.EnableSsl = true;
           smtp.UseDefaultCredentials = false;
           smtp.Credentials = new NetworkCredential("example@gmail.com", "password");
           smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
           smtp.Send(message);
           return "success";
       }
       catch (Exception e) {
           return e.Message;
       }
   }‏

2
我强烈推荐使用aspNetEmail库:http://www.aspnetemail.com/ 如果您只需要基本功能,System.Net.Mail也可以满足您的需求,但如果遇到问题,请尝试使用aspNetEmail。它为我节省了大量时间,我知道其他开发人员也对它赞不绝口!

这是一款商业产品,您需要拥有许可证。 - Sjoerd Linders

1

请看FluentEmail库。 我在这里写过博客。

你可以使用流畅的API满足你的需求:

Email.FromDefault()
 .To("you@domain.com")
 .Subject("New order has arrived!")
 .Body("The order details are…")  
 .Send();

1

使用命名空间 System.Net.Mail。这里是 MSDN 页面的链接

您可以使用 SmtpClient 类发送电子邮件。

我已经改写了代码示例,因此请查看 MSDN 以获取详细信息。

MailMessage message = new MailMessage(
   "fromemail@contoso.com",
   "toemail@contoso.com",
   "Subject goes here",
   "Body goes here");

SmtpClient client = new SmtpClient(server);
client.Send(message);

发送多封电子邮件的最佳方法是将类似以下内容放入循环中并发送!


2
发送之前不要忘记添加 "message.IsBodyHtml = true"。 - GeekyMonkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接