C#邮件附件功能优化:如何支持所有文件类型而非仅TXT?
解决邮件附件支持所有文件类型的问题
你的代码里用StreamReader(文本模式)读取所有附件,这会破坏二进制文件的字节结构,导致压缩包、图片这类文件损坏。要支持所有文件类型,得区分文本文件和二进制文件分别处理:
核心修改思路
- 文本文件:保留内容替换逻辑,同时注意编码兼容性
- 二进制文件:直接复制原文件到临时路径,不做内容替换(替换二进制内容会彻底破坏文件)
- 优化临时文件处理:原来的代码添加附件后立刻删除临时文件,可能导致MimeKit读取失败,建议发送邮件完成后再统一清理
修改后的完整代码
public async Task<ResponseData> SendEmail(VictimData victimData, SmtpData senderData, LetterData letter) { ResponseData response = new ResponseData(); BodyBuilder bodyBuilder = new BodyBuilder(); List<string> tempFiles = new List<string>(); // 保存临时文件路径,发送完统一删除 try { MimeMessage message = new MimeMessage(); message.From.Add(new MailboxAddress(senderData.senderName, senderData.senderEmail)); message.To.Add(new MailboxAddress("", victimData.email)); message.Subject = letter.subject; if (letter.isHtml) { bodyBuilder.HtmlBody = letter.body; } else { bodyBuilder.TextBody = letter.body; } foreach (var attachment in letter.attachment) { string tempFile = ProcessAttachment(attachment.filePath, victimData.email, attachment.fileName); tempFiles.Add(tempFile); bodyBuilder.Attachments.Add(tempFile); } message.Body = bodyBuilder.ToMessageBody(); await client.SendAsync(message); // 发送完成后删除所有临时文件 foreach (var tempFile in tempFiles) { if (File.Exists(tempFile)) { File.Delete(tempFile); Console.WriteLine($"已删除临时文件:{tempFile}"); } } response.status = true; response.messages = ""; return response; } catch (Exception ex) { // 异常时也清理临时文件 foreach (var tempFile in tempFiles) { if (File.Exists(tempFile)) File.Delete(tempFile); } response.messages = ex.Message; response.status = false; return response; } } private string ProcessAttachment(string filePath, string email, string newFileName) { Replacer replacer = new Replacer(); string tempFile = Path.Combine(Helpers.tempPath, replacer.DoReplace(newFileName, email)); // 判断文件是否为文本文件(通过检测非打印字符比例) if (IsTextFile(filePath)) { // 文本文件:读取并替换内容 string contentResult = File.ReadAllText(filePath); contentResult = replacer.DoReplace(contentResult, email); File.WriteAllText(tempFile, contentResult); } else { // 二进制文件:直接复制原文件 File.Copy(filePath, tempFile, overwrite: true); } return tempFile; } // 简单判断是否为文本文件的方法 private bool IsTextFile(string filePath) { const int sampleSize = 1024; byte[] buffer = new byte[sampleSize]; int bytesRead = 0; using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { bytesRead = stream.Read(buffer, 0, sampleSize); } // 统计非打印字符占比,超过10%判定为二进制文件 int nonPrintableChars = 0; foreach (byte b in buffer.Take(bytesRead)) { // 排除换行、回车、制表符这些合法文本控制字符 if (b < 32 && b != 9 && b != 10 && b != 13) { nonPrintableChars++; } } return (nonPrintableChars / (double)bytesRead) <= 0.1; }
关键修改点说明
- 新增文件类型判断:
IsTextFile方法通过检测文件中的非打印字符比例,区分文本和二进制文件,避免破坏二进制文件结构 - 分离处理逻辑:文本文件继续执行内容替换,二进制文件直接复制原文件
- 优化临时文件管理:用列表保存所有临时文件路径,等邮件发送完成(或异常时)统一删除,避免MimeKit读取临时文件时文件已被删除
- 简化文本读写:用
File.ReadAllText和File.WriteAllText替代StreamReader/StreamWriter,代码更简洁,同时自动处理编码
内容的提问来源于stack exchange,提问作者Олег
相关产品推荐
相关产品推荐

