.net 邮件批量发送功能源码
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.net 邮件批量发送功能源码相关的知识,希望对你有一定的参考价值。
#define debug
using
System;
using
System.Text;
using
System.Linq;
using
System.IO;
using
System.Net;
using
System.Net.Mail;
using
System.Net.Mime;
using
System.Threading;
using
System.ComponentModel;
using
System.Diagnostics;
using
System.Collections.Generic;
using
System.Collections.Concurrent;
using
System.Collections.ObjectModel;
namespace
Mail_Test.Mail
{
/// <summary>
/// 非线程安全类
/// 使用注意事项:
/// 1、该类无需(也不能)在外部包裹多线程,因为内部有提供“异步发送”方法,内、外都使用多线程会导致线程池对可用资源的误判,从而创建过多阻塞线程。
/// 2、MailHelper类的 m_autoDisposeSmtp 属性的使用,具体见此字段注释。
/// 3、启用 UTF-8 字符编码
/// </summary>
public
class
MailHelper
{
#region 构造函数
/// <summary>
/// 构建 MailHelper 实例
/// </summary>
/// <param name="isAsync">是否启用异步邮件发送,默认为同步发送</param>
public
MailHelper(
bool
isAsync =
false
)
{
m_IsAsync = isAsync;
}
/// <summary>
/// 构建 MailHelper 实例
/// </summary>
/// <param name="mSmtpClient">SmtpClient实例</param>
/// <param name="autoReleaseSmtp">是否自动释放SmtpClient实例</param>
/// <param name="isAsync">是否启用异步邮件发送</param>
public
MailHelper(SmtpClient mSmtpClient,
bool
autoReleaseSmtp,
bool
isAsync =
false
)
{
this
.SetSmtpClient(mSmtpClient, autoReleaseSmtp);
m_IsAsync = isAsync;
}
#endregion
#region 计划邮件数量 和 已执行完成邮件数量
// 记录和获取在大批量执行异步短信发送时已经处理了多少条记录
// 1、根据此值手动或自动释放 SmtpClient .实际上没有需要根据此值进行手动释放,因为完全可以用自动释放替换此逻辑
// 2、根据此值可以自己设置进度
private
long
m_CompletedSendCount = 0;
public
long
CompletedSendCount
{
get
{
return
Interlocked.Read(
ref
m_CompletedSendCount); }
private
set
{ Interlocked.Exchange(
ref
m_CompletedSendCount, value); }
}
// 计划邮件数量
private
long
m_PrepareSendCount = 0;
public
long
PrepareSendCount
{
get
{
return
Interlocked.Read(
ref
m_PrepareSendCount); }
private
set
{ Interlocked.Exchange(
ref
m_PrepareSendCount, value); }
}
#endregion
#region 异步 发送邮件相关参数
// 是否启用异步发送邮件
private
bool
m_IsAsync =
false
;
// 案例:因为异步发送邮件在SmtpClient处必须加锁保证一封一封的发送。
// 这样阻塞了主线程。所以换用队列的方式以无阻塞的方式进行异步发送大批量邮件
// 发送任务可能很长,所以使用 Thread 而不是用ThreadPool。(避免长时间暂居线程池线程),并且SmtpClient只支持一次一封邮件发送
private
Thread m_SendMailThread =
null
;
private
AutoResetEvent m_AutoResetEvent =
null
;
private
AutoResetEvent AutoResetEvent
{
get
{
if
(m_AutoResetEvent ==
null
)
m_AutoResetEvent =
new
AutoResetEvent(
true
);
return
m_AutoResetEvent;
}
}
// 待发送队列缓存数量。单独开个计数是为了提高获取此计数的效率
private
int
m_messageQueueCount = 0;
// 因为 MessageQueue 可能在 m_SendMailThread 线程中进行出队操作,所以使用并发队列ConcurrentQueue.
// 队列中的数据只能通过取消异步发送进行清空,或则就会每一元素都执行发送邮件
private
ConcurrentQueue<MailUserState> m_MessageQueue =
null
;
private
ConcurrentQueue<MailUserState> MessageQueue
{
get
{
if
(m_MessageQueue ==
null
)
m_MessageQueue =
new
ConcurrentQueue<MailUserState>();
return
m_MessageQueue;
}
}
/// <summary>
/// 在执行异步发送时传递的对象,用于传递给异步发生完成时调用的方法 OnSendCompleted 。
/// </summary>
public
object
AsycUserState {
get
;
set
; }
#endregion
#region 内部字段、属性
private
SmtpClient m_SmtpClient =
null
;
/// <summary>
/// 默认为false。设置在 MailHelper 类内部,发送完邮件后是否自动释放 SmtpClient 实例
/// Smtp不管是在 MailHelper 内部还是在外部都必须进行主动释放,
/// 因为:SmtpClient 没有提供 Finalize() 终结器,所以GC不会进行回收,只能使用完后主动进行释放,否则会发生内存泄露问题。
///
/// 何时将 autoReleaseSmtp 设置为false,就是SmtpClient需要重复使用的情况,即需要使用“相同MailHelper”向“相同Smtp服务器”发送大批量的邮件时。
/// </summary>
private
bool
m_autoDisposeSmtp =
false
;
/// <summary>
/// 设置此电子邮件的收件人的地址集合。
/// </summary>
Dictionary<
string
,
string
> m_DicTo =
null
;
Dictionary<
string
,
string
> DicTo
{
get
{
if
(m_DicTo ==
null
)
m_DicTo =
new
Dictionary<
string
,
string
>();
return
m_DicTo;
}
}
/// <summary>
/// 设置此电子邮件的抄送 (CC) 收件人的地址集合。
/// </summary>
Dictionary<
string
,
string
> m_DicCC =
null
;
Dictionary<
string
,
string
> DicCC
{
get
{
if
(m_DicCC ==
null
)
m_DicCC =
new
Dictionary<
string
,
string
>();
return
m_DicCC;
}
}
/// <summary>
/// 设置此电子邮件的密件抄送 (BCC) 收件人的地址集合。
/// </summary>
Dictionary<
string
,
string
> m_DicBcc =
null
;
Dictionary<
string
,
string
> DicBcc
{
get
{
if
(m_DicBcc ==
null
)
m_DicBcc =
new
Dictionary<
string
,
string
>();
return
m_DicBcc;
}
}
// 附件集合
Collection<Attachment> m_Attachments;
Collection<Attachment> Attachments
{
get
{
if
(m_Attachments ==
null
)
m_Attachments =
new
Collection<Attachment>();
return
m_Attachments;
}
}
// 指定一个电子邮件不同格式显示的副本。
Collection<AlternateView> m_AlternateViews;
Collection<AlternateView> AlternateViews
{
get
{
if
(m_AlternateViews ==
null
)
m_AlternateViews =
new
Collection<AlternateView>();
return
m_AlternateViews;
}
}
#endregion
#region 公开属性
/// <summary>
/// 设置此电子邮件的发信人地址。
/// </summary>
public
string
From {
get
;
set
; }
/// <summary>
/// 设置此电子邮件的发信人地址。
/// </summary>
public
string
FromDisplayName {
get
;
set
; }
/// <summary>
/// 设置此电子邮件的主题。
/// </summary>
public
string
Subject {
get
;
set
; }
/// <summary>
/// 设置邮件正文。
/// </summary>
public
string
Body {
get
;
set
; }
/// <summary>
/// 设置邮件正文是否为 html 格式的值。
/// </summary>
public
bool
IsBodyHtml {
get
;
set
; }
private
int
priority = 0;
/// <summary>
/// 设置此电子邮件的优先级 0-Normal 1-Low 2-High
/// 默认Normal。
/// </summary>
public
int
Priority
{
get
{
return
this
.priority; }
set
{
if
(value < 0 || value > 2)
priority = 0;
else
priority = value;
}
}
#endregion
/// <summary>
/// 重置 MailHelper 实例信息
/// 不释放 SmtpClient 实例和相关的AutoReleaseSimple字段,因为存在异步发送。。这两个字段由SetSmtpClient方法设置
/// </summary>
public
void
Reset()
{
From = String.Empty;
FromDisplayName = String.Empty;
if
(m_DicTo !=
null
)
m_DicTo.Clear();
if
(m_DicCC !=
null
)
m_DicCC.Clear();
if
(m_DicBcc !=
null
)
m_DicBcc.Clear();
if
(m_Attachments !=
null
)
m_Attachments.Clear();
if
(m_AlternateViews !=
null
)
m_AlternateViews.Clear();
Subject = String.Empty;
Body = String.Empty;
IsBodyHtml =
false
;
priority = 0;
AsycUserState =
null
;
// 1、不重置SmtpClient。根据 m_autoDisposeSmtp 参数自动释放或由外部主动释放
// 2、不重置:异步待发送队列及队列计数,AutoResetEvent实例,执行异步发送线程,是否启用异步发送标识
}
#region SmtpClient 相关方法
/// <summary>
/// 检查此 MailHelper 实例是否已经设置了 SmtpClient
/// </summary>
/// <returns>true代表已设置</returns>
public
bool
ExistsSmtpClient()
{
return
m_SmtpClient !=
null
?
true
:
false
;
}
/// <summary>
/// 设置 SmtpClient 实例 和是否自动释放Smtp的唯一入口
/// 1、将内部 计划数量 和 已完成数量 清零,重新统计以便自动释放SmtpClient
/// 2、若要对SmtpClent设置SendCompleted事件,请在调用此方法前进行设置
/// </summary>
/// <param name="mSmtpClient"> SmtpClient 实例</param>
/// <param name="autoReleaseSmtp">设置在 MailHelper 类内部,发送完邮件后是否自动释放 SmtpClient 实例</param>
public
void
SetSmtpClient(SmtpClient mSmtpClient,
bool
autoReleaseSmtp)
{
#if DEBUG
Debug.WriteLine(
"设置SmtpClient,自动释放为"
(autoReleaseSmtp ?
"TRUE"
:
"FALSE"
));
#endif
m_SmtpClient = mSmtpClient;
m_autoDisposeSmtp = autoReleaseSmtp;
// 将内部 计划数量 和 已完成数量 清零,重新统计以便自动释放SmtpClient (MailHelper实例唯一的清零地方)
m_PrepareSendCount = 0;
m_CompletedSendCount = 0;
if
(m_IsAsync && autoReleaseSmtp)
{
// 注册内部释放回调事件.释放对象---该事件不进行取消注册,只在释放SmtpClient时,一起释放 (所以SmtpClient与MailHelper绑定后,就不要再单独使用了)