C#郵件發(fā)送與附件處理過(guò)程詳解
郵件發(fā)送基礎(chǔ)概念
什么是郵件發(fā)送?
郵件發(fā)送是通過(guò)網(wǎng)絡(luò)將電子信息從一個(gè)用戶發(fā)送到另一個(gè)用戶的過(guò)程。在編程中,我們通常使用SMTP 協(xié)議來(lái)實(shí)現(xiàn)郵件發(fā)送功能。
郵件發(fā)送的基本流程
發(fā)件人 → SMTP服務(wù)器 → 收件人郵件服務(wù)器 → 收件人
核心組成部分
1. 發(fā)件人信息:郵箱地址、顯示名稱? 2. 收件人信息:郵箱地址(可以多個(gè))? 3. 郵件內(nèi)容:主題、正文? 4. 附件:可選的文件附加? 5. SMTP 服務(wù)器配置:服務(wù)器地址、端口、認(rèn)證信息
SMTP 協(xié)議簡(jiǎn)介
什么是 SMTP?
**SMTP (Simple Mail Transfer Protocol)** 是簡(jiǎn)單郵件傳輸協(xié)議,是用于發(fā)送電子郵件的標(biāo)準(zhǔn)協(xié)議。
常見 SMTP 服務(wù)器配置
| 服務(wù)商 | SMTP 服務(wù)器 | 端口 | SSL |
|---|---|---|---|
| 阿里云 | smtpdm.aliyun.com | 80/465 | 80 端口不使用 SSL,465 端口使用 SSL |
| 騰訊企業(yè)郵 | smtp.exmail.qq.com | 465 | 是 |
為什么需要認(rèn)證?
SMTP 服務(wù)器通常需要用戶名和密碼認(rèn)證,以防止垃圾郵件發(fā)送和未授權(quán)使用。
C# 郵件發(fā)送核心類庫(kù)
System.Net.Mail 命名空間?
C# 提供了專門的命名空間用于郵件發(fā)送:
using System.Net; using System.Net.Mail; using System.Net.Mime;
核心類介紹
1. MailMessage 類?
用于構(gòu)建郵件消息的內(nèi)容和結(jié)構(gòu)。
MailMessage mail = new MailMessage();
mail.From = new MailAddress("sender@example.com", "發(fā)件人顯示名稱");
mail.To.Add("recipient@example.com");
mail.Subject = "郵件主題";
mail.Body = "郵件正文內(nèi)容";
mail.IsBodyHtml = true; // 是否支持HTML格式
2. SmtpClient 類?
用于通過(guò) SMTP 服務(wù)器發(fā)送郵件。
SmtpClient smtpClient = new SmtpClient("smtp.server.com", 587);
smtpClient.Credentials = new NetworkCredential("username", "password");
smtpClient.EnableSsl = true;
smtpClient.Send(mail);
3. Attachment 類
Attachment attachment = new Attachment("file.txt");
mail.Attachments.Add(attachment);
基礎(chǔ)郵件發(fā)送實(shí)現(xiàn)
最簡(jiǎn)單的郵件發(fā)送示例
using System;
using System.Net;
using System.Net.Mail;
class SimpleEmailSender
{
static void Main(string[] args)
{
try
{
// 1. 創(chuàng)建郵件消息
MailMessage mail = new MailMessage();
mail.From = new MailAddress("your-email@example.com", "你的名稱");
mail.To.Add("recipient@example.com");
mail.Subject = "測(cè)試郵件";
mail.Body = "這是一封測(cè)試郵件!";
mail.IsBodyHtml = false;
// 2. 配置SMTP客戶端
SmtpClient smtpClient = new SmtpClient("smtp.server.com", 587);
smtpClient.Credentials = new NetworkCredential("your-email@example.com", "your-password");
smtpClient.EnableSsl = true;
// 3. 發(fā)送郵件
smtpClient.Send(mail);
Console.WriteLine("郵件發(fā)送成功!");
}
catch (Exception ex)
{
Console.WriteLine($"郵件發(fā)送失敗: {ex.Message}");
}
}
}
關(guān)鍵代碼解釋?
- MailMessage 對(duì)象創(chuàng)建:構(gòu)建郵件的基本信息?
- SmtpClient 配置:設(shè)置 SMTP 服務(wù)器信息和認(rèn)證?
- 異常處理:捕獲可能的發(fā)送錯(cuò)誤
業(yè)務(wù)中完整的郵件發(fā)送工具類封裝
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Text;
namespace Tools.Mail
{
/// <summary>
/// SMTP郵件發(fā)送器,支持發(fā)送帶附件的郵件
/// </summary>
public static class SmtpEmailHelper
{
#region 配置參數(shù)
// SMTP服務(wù)器配置
private const string SmtpServer = " ";
private const int SmtpPort = 80;
private const bool EnableSsl = false;
// 發(fā)件人信息
private const string FromAddress = "system@example.com";
private const string FromDisplayName = "系統(tǒng)通知";
private const string SmtpUsername = "system@example.com";
private const string SmtpPassword = "your-password";
// 附件配置
private const int MaxAttachmentSize = 8 * 1024 * 1024; // 單個(gè)附件最大8MB
private const int MaxTotalAttachmentSize = 12 * 1024 * 1024; // 總附件大小限制
#endregion
#region 附件數(shù)據(jù)結(jié)構(gòu)
/// <summary>
/// 郵件附件信息
/// </summary>
public class EmailAttachment
{
/// <summary>
/// 文件名
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 文件內(nèi)容(字節(jié)數(shù)組)
/// </summary>
public byte[] Content { get; set; }
/// <summary>
/// 內(nèi)容類型
/// </summary>
public string ContentType { get; set; }
}
#endregion
#region 發(fā)送郵件方法
/// <summary>
/// 發(fā)送帶附件的郵件
/// </summary>
/// <param name="toAddress">收件人地址(多個(gè)用逗號(hào)分隔)</param>
/// <param name="subject">郵件主題</param>
/// <param name="htmlBody">HTML郵件正文</param>
/// <param name="attachments">附件列表</param>
public static void SendEmailWithAttachments(string toAddress, string subject,
string htmlBody, List<EmailAttachment> attachments = null)
{
try
{
// 創(chuàng)建郵件消息
MailMessage mail = CreateMailMessage(toAddress, subject, htmlBody);
// 添加附件
if (attachments != null && attachments.Any())
{
AddAttachmentsToMail(mail, attachments);
}
// 發(fā)送郵件
SendMail(mail);
}
catch (Exception ex)
{
Console.WriteLine($"郵件發(fā)送失敗: {ex.Message}");
throw;
}
}
#endregion
#region 郵件創(chuàng)建
private static MailMessage CreateMailMessage(string toAddress, string subject, string htmlBody)
{
MailMessage mail = new MailMessage();
// 發(fā)件人
mail.From = new MailAddress(FromAddress, FromDisplayName, Encoding.UTF8);
// 收件人
foreach (string receiver in toAddress.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
mail.To.Add(new MailAddress(receiver.Trim()));
}
// 郵件主題
mail.Subject = subject;
mail.SubjectEncoding = Encoding.UTF8;
// 郵件正文(HTML格式)
mail.Body = htmlBody;
mail.BodyEncoding = Encoding.UTF8;
mail.IsBodyHtml = true;
// 優(yōu)先級(jí)
mail.Priority = MailPriority.High;
return mail;
}
#endregion
#region 附件處理
private static void AddAttachmentsToMail(MailMessage mail, List<EmailAttachment> attachments)
{
long totalAttachmentSize = 0;
foreach (var attachment in attachments)
{
if (attachment == null || attachment.Content == null || attachment.Content.Length == 0)
continue;
// 檢查單個(gè)附件大小
if (attachment.Content.Length > MaxAttachmentSize)
{
Console.WriteLine($"附件 {attachment.FileName} 太大,跳過(guò)添加");
continue;
}
// 檢查總附件大小
if (totalAttachmentSize + attachment.Content.Length > MaxTotalAttachmentSize)
{
Console.WriteLine($"總附件大小超出限制,跳過(guò)添加附件 {attachment.FileName}");
break;
}
try
{
// 創(chuàng)建附件
Attachment mailAttachment = new Attachment(
new MemoryStream(attachment.Content),
attachment.FileName,
attachment.ContentType ?? "application/octet-stream"
);
// 設(shè)置附件屬性
ContentDisposition disposition = mailAttachment.ContentDisposition;
disposition.CreationDate = DateTime.Now;
disposition.ModificationDate = DateTime.Now;
disposition.ReadDate = DateTime.Now;
disposition.FileName = attachment.FileName;
disposition.Size = attachment.Content.Length;
disposition.DispositionType = DispositionTypeNames.Attachment;
mail.Attachments.Add(mailAttachment);
totalAttachmentSize += attachment.Content.Length;
Console.WriteLine($"添加附件成功: {attachment.FileName}");
}
catch (Exception ex)
{
Console.WriteLine($"添加附件 {attachment.FileName} 失敗: {ex.Message}");
}
}
}
#endregion
#region 郵件發(fā)送
private static void SendMail(MailMessage mail)
{
using (SmtpClient smtpClient = new SmtpClient(SmtpServer, SmtpPort))
{
smtpClient.EnableSsl = EnableSsl;
smtpClient.Credentials = new NetworkCredential(SmtpUsername, SmtpPassword);
smtpClient.Timeout = 300000; // 5分鐘超時(shí)
smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
// 發(fā)送郵件
smtpClient.Send(mail);
}
Console.WriteLine($"郵件發(fā)送成功,收件人: {string.Join(",", mail.To.Select(t => t.Address))}");
}
#endregion
}
}
封裝的優(yōu)勢(shì)?
- 職責(zé)單一:每個(gè)方法只負(fù)責(zé)一個(gè)具體功能?
- 錯(cuò)誤處理:統(tǒng)一的異常處理機(jī)制?
- 配置集中:所有配置參數(shù)集中管理?
- 易于使用:簡(jiǎn)潔的公共接口
實(shí)際業(yè)務(wù)應(yīng)用
業(yè)務(wù)場(chǎng)景分析
以企業(yè)批次處理報(bào)告郵件為例,我們需要:?
- 準(zhǔn)備業(yè)務(wù)數(shù)據(jù)?
- 生成郵件內(nèi)容?
- 創(chuàng)建附件(報(bào)告文件)?
- 發(fā)送郵件
業(yè)務(wù)數(shù)據(jù)模型設(shè)計(jì)
/// <summary>
/// 批次報(bào)告數(shù)據(jù)模型
/// 包含所有生成報(bào)告所需的業(yè)務(wù)數(shù)據(jù)
/// </summary>
public class BatchReportData
{
public int Batch { get; set; } // 批次號(hào)
public int Year { get; set; } // 年份
public int TotalCount { get; set; } // 總企業(yè)數(shù)
public int SuccessCount { get; set; } // 成功處理數(shù)
public int ErrorCount { get; set; } // 錯(cuò)誤數(shù)
public int UnobtainedCount { get; set; } // 未獲取數(shù)
public List<BatchRecordModel> AbnormalRecords { get; set; } // 異常記錄
public List<BatchRecordModel> UnobtainedRecords { get; set; } // 未獲取記錄
public List<string> ErrorLogs { get; set; } // 錯(cuò)誤日志
public string Receivers { get; set; } // 收件人列表
public DateTime GenerateTime { get; set; } // 生成時(shí)間
}
業(yè)務(wù)邏輯實(shí)現(xiàn)
1. 數(shù)據(jù)準(zhǔn)備
/// <summary>
/// 準(zhǔn)備批次報(bào)告所需的業(yè)務(wù)數(shù)據(jù)
/// </summary>
private BatchReportData PrepareBatchReportData(int batch, List<string> errors)
{
// 1. 獲取當(dāng)前年份
int year = DateTime.Now.Year;
// 2. 查詢批次記錄
List<BatchRecordModel> batchRecords = _enterpriseProvider.GetBatchRecords(batch, year);
if (!batchRecords.Any())
{
Logger.Warn($"批次{batch}年度{year}沒(méi)有找到記錄");
return null;
}
// 3. 統(tǒng)計(jì)數(shù)據(jù)
int totalCount = batchRecords.Count;
int successCount = batchRecords.Count(r => r.Status == 1);
int errorCount = batchRecords.Count(r => r.Status == 2);
int unobtainedCount = batchRecords.Count(r => r.Status == 0);
// 4. 獲取異常和未獲取記錄
List<BatchRecordModel> abnormalRecords = batchRecords.Where(r => r.HasAbnormalData == 1).ToList();
List<BatchRecordModel> unobtainedRecords = batchRecords.Where(r => r.Status == 0).ToList();
// 5. 獲取收件人配置
string receivers = _configProvider.GetEmailReceivers();
return new BatchReportData
{
Batch = batch,
Year = year,
TotalCount = totalCount,
SuccessCount = successCount,
ErrorCount = errorCount,
UnobtainedCount = unobtainedCount,
AbnormalRecords = abnormalRecords,
UnobtainedRecords = unobtainedRecords,
ErrorLogs = errors ?? new List<string>(),
Receivers = receivers,
GenerateTime = DateTime.Now
};
}
2. HTML 郵件內(nèi)容生成
/// <summary>
/// 生成HTML格式的郵件正文
/// </summary>
private string GenerateEmailHtmlBody(BatchReportData reportData)
{
StringBuilder htmlBuilder = new StringBuilder();
htmlBuilder.AppendLine("<!DOCTYPE html>");
htmlBuilder.AppendLine("<html lang='zh-CN'>");
htmlBuilder.AppendLine("<head>");
htmlBuilder.AppendLine("<meta charset='UTF-8'>");
htmlBuilder.AppendLine("<title>批次處理結(jié)果報(bào)告</title>");
htmlBuilder.AppendLine("<style>");
htmlBuilder.AppendLine("body { font-family: 'Microsoft YaHei', Arial, sans-serif; line-height: 1.6; }");
htmlBuilder.AppendLine(".container { max-width: 800px; margin: 0 auto; padding: 20px; }");
htmlBuilder.AppendLine(".header { background-color: #f5f5f5; padding: 15px; text-align: center; border-radius: 5px; }");
htmlBuilder.AppendLine(".content { margin: 20px 0; }");
htmlBuilder.AppendLine(".stats { background-color: #f9f9f9; padding: 15px; border-radius: 5px; margin: 15px 0; }");
htmlBuilder.AppendLine(".stat-item { margin: 8px 0; }");
htmlBuilder.AppendLine(".footer { text-align: center; margin-top: 30px; color: #666; font-size: 14px; }");
htmlBuilder.AppendLine("</style>");
htmlBuilder.AppendLine("</head>");
htmlBuilder.AppendLine("<body>");
htmlBuilder.AppendLine("<div class='container'>");
// 郵件頭部
htmlBuilder.AppendLine("<div class='header'>");
htmlBuilder.AppendLine($"<h2>批次處理結(jié)果報(bào)告 - 批次{reportData.Batch} ({reportData.Year}年度)</h2>");
htmlBuilder.AppendLine("</div>");
// 處理時(shí)間
htmlBuilder.AppendLine("<div class='content'>");
htmlBuilder.AppendLine($"<p>報(bào)告生成時(shí)間:{reportData.GenerateTime.ToString("yyyy-MM-dd HH:mm:ss")}</p>");
// 統(tǒng)計(jì)信息
htmlBuilder.AppendLine("<div class='stats'>");
htmlBuilder.AppendLine("<h3>處理統(tǒng)計(jì)</h3>");
htmlBuilder.AppendLine($"<div class='stat-item'>總企業(yè)數(shù):<strong>{reportData.TotalCount}</strong></div>");
htmlBuilder.AppendLine($"<div class='stat-item'>成功處理:<strong>{reportData.SuccessCount}</strong></div>");
htmlBuilder.AppendLine($"<div class='stat-item'>處理失?。?lt;strong>{reportData.ErrorCount}</strong></div>");
htmlBuilder.AppendLine($"<div class='stat-item'>未獲取信息:<strong>{reportData.UnobtainedCount}</strong></div>");
htmlBuilder.AppendLine("</div>");
// 異常企業(yè)信息
if (reportData.AbnormalRecords.Any())
{
htmlBuilder.AppendLine("<div class='stats'>");
htmlBuilder.AppendLine($"<h3>異常企業(yè) ({reportData.AbnormalRecords.Count}家)</h3>");
htmlBuilder.AppendLine("<p>以下企業(yè)存在經(jīng)營(yíng)異常或嚴(yán)重違法記錄,請(qǐng)及時(shí)處理。</p>");
htmlBuilder.AppendLine("</div>");
}
// 郵件底部
htmlBuilder.AppendLine("<div class='footer'>");
htmlBuilder.AppendLine("<p>此郵件為系統(tǒng)自動(dòng)發(fā)送,請(qǐng)勿回復(fù)。詳細(xì)信息請(qǐng)查看附件。</p>");
htmlBuilder.AppendLine("</div>");
htmlBuilder.AppendLine("</div>");
htmlBuilder.AppendLine("</div>");
htmlBuilder.AppendLine("</body>");
htmlBuilder.AppendLine("</html>");
return htmlBuilder.ToString();
}
3. 附件生成
/// <summary>
/// 生成報(bào)告附件
/// </summary>
private List<SmtpEmailHelper.EmailAttachment> GenerateReportAttachments(BatchReportData reportData)
{
List<SmtpEmailHelper.EmailAttachment> attachments = new List<SmtpEmailHelper.EmailAttachment>();
// 生成CSV格式的詳細(xì)報(bào)告
byte[] csvContent = GenerateCsvReport(reportData);
attachments.Add(new SmtpEmailHelper.EmailAttachment
{
FileName = $"批次{reportData.Batch}_處理報(bào)告_{reportData.GenerateTime:yyyyMMddHHmmss}.csv",
Content = csvContent,
ContentType = "text/csv"
});
// 生成錯(cuò)誤日志文件
if (reportData.ErrorLogs.Any())
{
byte[] errorLogContent = GenerateErrorLogFile(reportData);
attachments.Add(new SmtpEmailHelper.EmailAttachment
{
FileName = $"批次{reportData.Batch}_錯(cuò)誤日志_{reportData.GenerateTime:yyyyMMddHHmmss}.txt",
Content = errorLogContent,
ContentType = "text/plain"
});
}
return attachments;
}
/// <summary>
/// 生成CSV格式報(bào)告
/// </summary>
private byte[] GenerateCsvReport(BatchReportData reportData)
{
using (MemoryStream ms = new MemoryStream())
using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8))
{
// CSV頭部
writer.WriteLine("企業(yè)名稱,統(tǒng)一社會(huì)信用代碼,處理狀態(tài),異常類型,獲取時(shí)間,備注");
// 處理數(shù)據(jù)行
foreach (var record in reportData.AbnormalRecords)
{
string status = record.Status == 1 ? "成功" : record.Status == 2 ? "失敗" : "未處理";
string abnormalType = record.HasRegStatusAbnormal == 1 ? "經(jīng)營(yíng)異常" :
record.HasIllegalData == 1 ? "嚴(yán)重違法" : "其他異常";
writer.WriteLine($"{CsvEncode(record.FacName)},{CsvEncode(record.FacCode)},{status},{abnormalType},{record.UpdateTime:yyyy-MM-dd HH:mm:ss},");
}
writer.Flush();
return ms.ToArray();
}
}
/// <summary>
/// 生成錯(cuò)誤日志文件
/// </summary>
private byte[] GenerateErrorLogFile(BatchReportData reportData)
{
using (MemoryStream ms = new MemoryStream())
using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8))
{
writer.WriteLine($"批次{reportData.Batch}錯(cuò)誤日志");
writer.WriteLine($"生成時(shí)間:{reportData.GenerateTime:yyyy-MM-dd HH:mm:ss}");
writer.WriteLine($"錯(cuò)誤總數(shù):{reportData.ErrorLogs.Count}");
writer.WriteLine();
writer.WriteLine("錯(cuò)誤詳情:");
writer.WriteLine();
for (int i = 0; i < reportData.ErrorLogs.Count; i++)
{
writer.WriteLine($"錯(cuò)誤 {i + 1}:");
writer.WriteLine(reportData.ErrorLogs[i]);
writer.WriteLine();
writer.WriteLine("-".PadRight(60, '-'));
writer.WriteLine();
}
writer.Flush();
return ms.ToArray();
}
}
/// <summary>
/// CSV編碼處理
/// </summary>
private string CsvEncode(string value)
{
if (string.IsNullOrEmpty(value))
return string.Empty;
// CSV編碼規(guī)則:如果包含逗號(hào)、引號(hào)或換行符,需要用雙引號(hào)括起來(lái)
if (value.Contains(",") || value.Contains("\"") || value.Contains("\n") || value.Contains("\r"))
{
return "\"" + value.Replace("\"", "\"\"") + "\"";
}
return value;
}
4. 業(yè)務(wù)方法調(diào)用
/// <summary>
/// 發(fā)送批次處理結(jié)果郵件報(bào)告(帶附件版本)
/// 業(yè)務(wù)邏輯:準(zhǔn)備數(shù)據(jù) -> 生成內(nèi)容 -> 調(diào)用郵件發(fā)送器
/// </summary>
public void SendBatchProcessNotification(int batch, List<string> errors)
{
try
{
// 1. 業(yè)務(wù)數(shù)據(jù)準(zhǔn)備
var reportData = PrepareBatchReportData(batch, errors);
if (reportData == null)
{
Logger.Warn($"批次{batch}沒(méi)有數(shù)據(jù)需要發(fā)送");
return;
}
// 2. 生成郵件內(nèi)容(業(yè)務(wù)邏輯)
string emailSubject = $"批次{reportData.Batch}處理結(jié)果報(bào)告 - {reportData.Year}年度";
string htmlBody = GenerateEmailHtmlBody(reportData);
// 3. 生成附件(業(yè)務(wù)邏輯)
var attachments = GenerateReportAttachments(reportData);
// 4. 調(diào)用獨(dú)立的郵件發(fā)送器(不包含業(yè)務(wù)邏輯)
SendEmailThroughSmtp(reportData.Receivers, emailSubject, htmlBody, attachments);
Logger.Info($"批次{batch}帶附件處理結(jié)果郵件已發(fā)送");
}
catch (Exception ex)
{
Logger.Error($"發(fā)送批次{batch}帶附件郵件報(bào)告失敗: {ex.Message}", ex);
}
}
/// <summary>
/// 通過(guò)SMTP發(fā)送郵件(僅負(fù)責(zé)調(diào)用,不包含業(yè)務(wù)邏輯)
/// </summary>
private void SendEmailThroughSmtp(string receivers, string subject, string htmlBody,
List<SmtpEmailHelper.EmailAttachment> attachments)
{
try
{
// 直接調(diào)用獨(dú)立的郵件發(fā)送器
SmtpEmailHelper.SendEmailWithAttachments(receivers, subject, htmlBody, attachments);
}
catch (Exception ex)
{
Logger.Error($"SMTP郵件發(fā)送器調(diào)用失敗: {ex.Message}", ex);
throw;
}
}
5. 最終結(jié)果

以上就是C#郵件發(fā)送與附件處理過(guò)程詳解的詳細(xì)內(nèi)容,更多關(guān)于C#郵件發(fā)送與附件處理的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#實(shí)現(xiàn)WebAPI接口安全加密的具體方案
在項(xiàng)目開發(fā)過(guò)程中,接口的安全性往往是一個(gè)容易被忽視但極其關(guān)鍵的環(huán)節(jié),本文介紹了一套實(shí)際項(xiàng)目中已落地的?Web?API?安全加密方案,涵蓋了?SHA256?加簽、RSA?非對(duì)稱加密、AES?對(duì)稱加密?以及相關(guān)數(shù)據(jù)格式轉(zhuǎn)換等內(nèi)容,需要的朋友可以參考下2025-06-06
C#利用WebClient實(shí)現(xiàn)兩種方式下載文件
本篇文章主要介紹了C#利用WebClient 兩種方式下載文件,詳細(xì)的介紹了兩種方式,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。2017-02-02
c#獲取光標(biāo)在屏幕中位置的簡(jiǎn)單實(shí)例
這篇文章主要介紹了c#獲取光標(biāo)在屏幕中位置的簡(jiǎn)單實(shí)例,有需要的朋友可以參考一下2013-12-12
C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法
這篇文章主要介紹了C#微信公眾號(hào)開發(fā)之接收事件推送與消息排重的方法,詳細(xì)分析了事件推送與消息排重的使用技巧,對(duì)微信開發(fā)有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-01-01

