65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 MSMQ 发送批量邮件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (14投票s)

2011年3月7日

CPOL

3分钟阅读

viewsIcon

67952

downloadIcon

6232

使用 MSMQ 发送批量邮件

引言

我正在开发一个 Web 应用程序;其中一个需求是向多个用户发送批量邮件。

之前,我使用 SMTP 客户端对象来发送邮件。但是当收件人数量增加时,应用程序会长时间卡住。此外,多个应用程序使用相同的 SMTP 服务器,因此服务器上的负载非常高。

为了优化性能,我在单独的服务器上使用 MSMQ 创建了一个新队列,所有邮件都排队,然后创建了一个应用程序,该应用程序将逐个读取电子邮件并通过 SMTP 客户端发送它。现在,我的原始 Web 应用程序不会直接连接到 SMTP 服务器,因此发送批量邮件的等待时间将非常短,并且 SMTP 服务器上的负载将减少。

背景

MSMQ 本质上是一种消息传递协议,允许在单独的服务器或进程上运行的应用程序以故障安全的方式进行通信。队列是一个临时存储位置,可以从中可靠地发送和接收消息。它们可用于跨异构网络以及可能不总是连接的计算机之间的通信。手动创建 MSMQ – 队列的步骤如下

  1. 右键单击“我的电脑”
  2. 单击“管理”
  3. 展开“服务和应用程序”
  4. 现在你可以看到“消息队列”
  5. 展开“专用队列”,单击“新建专用队列” – 输入名称“emailqueue”

这将创建一个新队列,请参阅随附的文档以获取详细信息。现在我们将了解如何以编程方式创建它。
请注意:所需的命名空间是:‘System.Messaging’ 用于 MSMQ 和 ‘System.Net.Mail' 用于使用 SMTP 客户端发送邮件。 此外,必须在你的计算机上安装 MSMQ。

Using the Code

现在我们将了解如何使用 MSMQ 以编程方式发送邮件。 我已将应用程序分为两部分

  1. 将创建 MSMQ 队列并将所有邮件信息作为对象保存的应用程序
  2. 将从队列中读取邮件信息并通过 SMTP 发送电子邮件的应用程序。

第一部分

首先,我们将了解电子邮件发送者部分:在这里,我创建了 Windows 窗体,它将从用户那里获取输入,例如“收件人地址”、“发件人地址”、“主题”、“正文”等。单击“发送按钮”后,从 EmailService 调用方法 QueueMessage

QueueMessage 用于创建事务性队列(如果它不存在),它还会将数据推入此队列中。

string msmqQueuePath = @".\Private$\EmailQueue";
// Create new instance of Message object
Message msmqMsg = new Message();

// Assign email information to the Message body
msmqMsg.Body = emailMessage;
//set Recoverable which indicates message is guaranteed 
msmqMsg.Recoverable = true;
//Set Formatter to serialize the object,I’m using binary //serialization
msmqMsg.Formatter = new BinaryMessageFormatter();
//Create message queue instance 
MessageQueue msmqQueue = new MessageQueue();
//If the Message queue does not exists at specified 
//location create it

if (!MessageQueue.Exists(msmqQueuePath))
{
    msmqQueue =  MessageQueue.Create(msmqQueuePath);
}
 
//  Set Formatter to serialize the object. 
msmqQueue.Formatter = new BinaryMessageFormatter();

//Send the message object in the created queue
msmqQueue.Send(msmqMsg);		

第二部分

电子邮件接收器

在这里,我创建了一个控制台应用程序,该应用程序将持续运行以读取任何新消息。

我们需要一个消息队列实例,它将从指定路径读取电子邮件消息对象。请注意,接收器中的消息路径必须与发送器中的消息路径相同。然后引发消息队列的接收完成事件。

as: _msmqQueue.ReceiveCompleted+= In msmqQueue_ReceiveCompleted event : 
extract the actual message like: (EmailEntities.EmailMessage)e.Message.Body. 

现在创建“MailMessage”的实例并设置相应的属性。 创建 SMTP 客户端的实例并调用 Send 方法。 这将从队列中发送实际的消息。

//message path must be same as sender
string messageQueuePath = @".\private$\EmailQueue";
//create message queue instance
                    _msmqQueue = new MessageQueue(messageQueuePath);
//set formatter same as sender
                    _msmqQueue.Formatter =  new BinaryMessageFormatter();
                    _msmqQueue.MessageReadPropertyFilter.SetAll();
//Raise receive completed event 
_msmqQueue.ReceiveCompleted+=new ReceiveCompletedEventHandler(msmqQueue_ReceiveCompleted);
//start receiving messages
                    _msmqQueue.BeginReceive();
//In msmqQueue_ReceiveCompleted
//Extract the actual message 
EmailEntities.EmailMessage emailMsg = (EmailEntities.EmailMessage)e.Message.Body;
//Create mail message instance 
MailMessage mailMesage = new MailMessage();
//Set the properties
mailMesage.Subject = emailMsg.Subject;
mailMesage.Body = emailMsg.Body;
//Create Smtp client instance
SmtpClient oclient = new SmtpClient();
//call the send method 
oclient.Send(mailMesage);

关注点

一些读者问我,我们如何在此邮件中添加附件?根据分析,我们无法直接序列化附件,但有替代方案

  1. 我们可以创建一个单独的类来帮助序列化整个附件:类似于
    class SerializeableAttachment 
    { String ContentId; SerializeableContentDisposition ContentDisposition; 
    SerializeableContentType ContentType; ..... 
  2. 与其序列化整个附件,不如将该附件存储在带有键值对的数据库中,并在发送电子邮件类中添加相应的属性。在接收器部分,读取附件的那个键并从数据库中获取实际附件。
    有关更多信息,请参阅 此链接

历史

  1. 初始版本
  2. 次要更改
  3. 小代码更改
© . All rights reserved.