如何用foreach循环实现C#多附件邮件发送?优化现有硬编码代码
优化C#邮件批量附件处理方案
Hey there! Let's fix that hardcoded attachment issue and make your code clean, scalable, and maintainable. Here's a step-by-step refactor:
1. 重构模型类(核心改进)
首先,我们要把那些重复的AttachmentContect1、AttachmentName1这类硬编码属性替换成一个附件列表,这样不管你要加1个还是10个附件,都不用修改模型结构。
先创建一个单独的附件项类,然后在EmailDetails里添加这个类的集合:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace Services.Models { public class CommonModel { // 新增:单个附件的实体类 public class AttachmentItem { public byte[] Content { get; set; } public string FileName { get; set; } } public class EmailDetails { public string ToMailId { get; set; } public string Subject { get; set; } public string Body { get; set; } public string CCList { get; set; } // 替换原来的单个附件属性为列表 public List<AttachmentItem> Attachments { get; set; } = new List<AttachmentItem>(); } } }
这样修改后,你的模型就具备了处理任意数量附件的能力,不用再每次加新的AttachmentContectN属性了。
2. 重构SendMail发送方法
接下来,把原来硬编码的两个附件判断逻辑,改成遍历附件列表的循环:
public static void SendMail(EmailDetails ObjEmailDtl){ try { SmtpClient client = new SmtpClient(); client.DeliveryMethod = SmtpDeliveryMethod.Network; client.EnableSsl = false; string hostName = string.Empty; using (eCoreDbEntities db = new eCoreDbEntities()) { hostName = db.Parameters.Where(m => m.Name == "SMTP").FirstOrDefault().Value; } client.Host = hostName; client.Port = 25; // 用using包裹MailMessage,自动释放资源 using (MailMessage msg = new MailMessage()) { msg.From = new MailAddress("contactus@karvyclick.com"); // 处理收件人(原有逻辑保留) if (!string.IsNullOrEmpty(ObjEmailDtl.ToMailId)) { string[] arrCC = ObjEmailDtl.ToMailId.Trim().Split(','); foreach (var item in arrCC) { msg.To.Add(new MailAddress(item)); } } // 处理抄送人(原有逻辑保留) if (!string.IsNullOrEmpty(ObjEmailDtl.CCList)) { string[] arrCC = ObjEmailDtl.CCList.Trim().Split(','); foreach (var item in arrCC) { msg.CC.Add(new MailAddress(item)); } } msg.Subject = ObjEmailDtl.Subject; msg.IsBodyHtml = true; msg.Body = ObjEmailDtl.Body; // 批量处理附件(替换原来的两个if判断) if (ObjEmailDtl.Attachments != null && ObjEmailDtl.Attachments.Any()) { foreach (var attachmentItem in ObjEmailDtl.Attachments) { // 跳过无效的附件(内容为空或文件名缺失) if (attachmentItem.Content == null || string.IsNullOrEmpty(attachmentItem.FileName)) { continue; } Attachment att = new Attachment(new MemoryStream(attachmentItem.Content), attachmentItem.FileName); msg.Attachments.Add(att); } } client.Send(msg); } } catch (Exception ex) { Common.WriteLog("Common-SendMail", "", ex.Message); } }
这里加了空值检查和无效附件跳过逻辑,还用using包裹了MailMessage,避免资源泄漏。
3. 修改调用代码(创建邮件部分)
最后,把原来创建单个附件的代码改成向列表中添加附件项:
byte[] dailyReportContent = Encoding.ASCII.GetBytes(str.ToString()); byte[] orderDetailsContent = Encoding.ASCII.GetBytes(str1.ToString()); EmailDetails objEmail = new EmailDetails(); var tomail = db.Parameters.ToList().Where(m => m.Name == "ToList" && m.Category == "DynamicReport").FirstOrDefault().Value; objEmail.ToMailId = tomail; // 添加第一个附件 objEmail.Attachments.Add(new CommonModel.AttachmentItem { Content = dailyReportContent, FileName = $"katalister_daily_report_{DateTime.Now:yyyyMMddHHmmss}.xls" }); // 添加第二个附件 objEmail.Attachments.Add(new CommonModel.AttachmentItem { Content = orderDetailsContent, FileName = "OrderDetails_BD.xls" }); objEmail.Subject = "Katalister Dynamic Report"; objEmail.Body = " Dear Leader,<br/><br/> Please find the attached Katalister Daily Report and Order Details Report.<br/><br/><br/><br/> Team Karvy"; objEmail.CCList = db.Parameters.ToList().Where(m => m.Name == "CCList" && m.Category == "DynamicReport").FirstOrDefault().Value; Common.SendMail(objEmail);
我把文件名里的DateTime.Now改成了格式化字符串yyyyMMddHHmmss,避免文件名里出现冒号这类系统不允许的字符。
额外小提示
- 编码注意:你现在用
Encoding.ASCII,如果报表内容包含非ASCII字符(比如中文、特殊符号),会出现乱码,建议改用Encoding.UTF8。 - 过时API提醒:
SmtpClient在.NET Framework中已经被标记为过时,如果你后续升级项目,建议改用更现代的MailKit库,它的API更友好,也支持更多功能。
内容的提问来源于stack exchange,提问作者kumar
相关产品推荐
相关产品推荐

