场景
- 当初客户要求给自己的营业部和营业所推送邮件(收件人超1000个)
- 邮件正文是去下载报表WORD(文件大小5M以上)数据文件转成HTML
- 三个附件文件也是要去报表上下载EXCEL(文件大小3M以上)
- 邮件要在10点之间推送完,但是这里报表的数据是8点以后ETL才刷好(数据刷好的时间不准确)
解决方案
- 1000个邮箱用循环去跑肯定慢;就算1分钟10封邮件也发不完;而且也没有这么高的性能
- 为了提高发送邮件的性能不得不去使用C#线程编程;我在这里使用了线程池这个东西,主要是因为线程池有队列、可以设置线程池中有多个线程一起做任务、线程池可以更好得控制CPU资源自己回收
A.SQL
CREATE DATABASE [SendEmailTest]
USE [SendEmailTest]
GO
CREATE TABLE [dbo].[mailboxUser](
[ID] [int] IDENTITY(1,1) NOT NULL,
[subject] [nvarchar](120) NULL,
[mailBody] [nvarchar](255) NULL,
[toEmail] [nvarchar](100) NULL,
[toEmailBCC] [nvarchar](100) NULL,
[State] [nchar](10) NULL,
[Creater] [nvarchar](100) NULL,
[CreateTime] [datetime] NULL,
[Updater] [nvarchar](100) NULL,
[UpdateTime] [datetime] NULL,
CONSTRAINT [PK_mailboxUser] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
DECLARE @count INT,@i INT
SET @count=120
SET @i=1
WHILE @i<=@count
BEGIN
INSERT INTO [mailboxUser] VALUES
(
'今天又是有希望得一天;'+CAST(@i AS NVARCHAR),
'今天要把任务做完;'+CAST(@i AS NVARCHAR),
'yincongpeng2019@163.com',
'',
'1',
'abel',
GETDATE(),
null,
null
)
SET @i=@i+1
END
B.控制台代码
class Program
{
private static string userEmail = ConfigHelper.GetConfigStr("userEmail"); //发件人邮箱
private static string userPswd = ConfigHelper.GetConfigStr("userPswd"); //邮箱帐号密码
private static string mailServer = ConfigHelper.GetConfigStr("mailServer"); //邮件服务器
private static string attachFilesPath = ConfigHelper.GetConfigStr("attachFilesPath"); //文件地址
private static string ServerDataDB = ConfigHelper.GetConfigStr("ServerDataDB");
static void Main(string[] args)
{
Console.WriteLine("------------------------------------------------------------------------------1.程序开始");
Stopwatch watch = new Stopwatch();
watch.Start(); //开始监视
ThreadUseAndConstruction();
//StartSendMail(1,"test","邮件发送测试", "yincongpeng2019@163.com","");
watch.Stop(); // 停止监视
Console.WriteLine("------------------------------------------------------------------------------2.程序结束");
TimeSpan timespan = watch.Elapsed; // 获取当前实例测量得出的总时间
Console.WriteLine("主线程运行结束;费时:" + timespan.TotalMilliseconds + "(总毫秒数)");
Console.ReadLine();
}
/// <summary>
/// 启动推送邮件线程池方法 2020-10-15 11:03 abel
/// </summary>
public static void ThreadUseAndConstruction()
{
//1.设置程序在运行时最小线程数和最大线程数
ThreadPool.SetMinThreads(1, 1);
ThreadPool.SetMaxThreads(5, 5);
//2.查询推送的邮箱用户
DataTable dt = new DbHelperSQL(ServerDataDB).Query(SelectMailboxUser_SQL).Tables[0];
for (int i = 0; i < dt.Rows.Count; i++)
{
int code = int.Parse(dt.Rows[i]["ID"].ToString());
string subject = dt.Rows[i]["subject"].ToString();
string mailBody = dt.Rows[i]["mailBody"].ToString();
string toEmail = dt.Rows[i]["toEmail"].ToString();
string toEmailBCC = dt.Rows[i]["toEmailBCC"].ToString();
//3.把推送邮件的方法放入WaitCallback委托
WaitCallback callback = index =>
{
Stopwatch watch = new Stopwatch();
watch.Start(); //开始监视
StartSendMail(code, subject, mailBody, toEmail, toEmailBCC);
watch.Stop(); // 停止监视
TimeSpan timespan = watch.Elapsed; // 获取当前实例测量得出的总时间
Console.WriteLine("编号:" + code + "的邮件推送结束;费时:" + timespan.TotalMilliseconds + "(总毫秒数)");
};
//4.在线程池中加入线程队列
ThreadPool.QueueUserWorkItem(callback, i);
}
}
/// <summary>
/// 开始推送邮件 2020-10-15 10:30 abel
/// </summary>
/// <param name="code">用户邮箱ID</param>
/// <param name="subject">主题</param>
/// <param name="mailBody">内容</param>
/// <param name="toEmail">接收人</param>
/// <param name="toEmailBCC">抄送人</param>
public static void StartSendMail(int code, string subject, string mailBody, string toEmail, string toEmailBCC)
{
bool SendState = new EmailHelper(toEmail, toEmailBCC, subject, mailBody, new string[0], userEmail, userPswd, mailServer).SendEmail();
if (SendState == true)
new DbHelperSQL(ServerDataDB).ExecuteSql(UpdateSendMailboxState_SQL, new SqlParameter[] { new SqlParameter("ID", code) });
}
/// <summary>
/// 查询推送的邮件用户 2020-10-15 10:52 abel
/// </summary>
private const string SelectMailboxUser_SQL = "select * from [dbo].[mailboxUser] where [State]=1";
/// <summary>
/// 更新邮件推送成功后的状态 2020-10-15 10:50 abel
/// </summary>
private const string UpdateSendMailboxState_SQL = "update [dbo].[mailboxUser] set [State]='0',[Updater]='abel_2',[UpdateTime]=getdate() where [ID]=@ID";
}
C.Achievements
资源
百度网盘链接地址:https://pan.baidu.com/s/1_vJB3tXta42t52f39fAiZQ
提取码:bhss