在PowerShell中纯内存创建Zip并邮件发送的问题排查
PowerShell纯内存创建Zip并作为邮件附件发送问题修复
问题1:无法向Zip条目写入内容
你的代码有两个核心问题导致写入失败:
- 仅关闭了
StreamWriter,未关闭ZipArchive——ZipArchive必须明确关闭才能完成压缩条目写入,否则内存中的Zip结构不完整 StreamWriter未强制刷新缓冲区,可能导致内容未全部写入条目流
修复方式:
- 用
using块自动管理StreamWriter和ZipArchive的生命周期,自动完成释放/关闭操作,避免手动遗漏 - 或手动调用
StreamWriter.Flush()后关闭,再确保关闭ZipArchive
问题2:Zip作为邮件附件的流处理
要在流关闭后保留内容用于附件,关键注意:
- 关闭
ZipArchive后,需将MemoryStream的位置重置到开头(Seek(0, 0)),否则邮件读取流时会从末尾开始,无法获取内容 - 创建
Attachment时必须指定附件文件名(如"log.zip"),否则收件端无法识别文件类型 - 确保
MemoryStream在邮件发送完成前不被释放,可通过using块或保持引用实现
完整修正代码
$strTextToZip = '<html><head><title>Log report</title></head><body><p>Paragraph</p><ul><li>first</li><li>second</li></ul></body></html>' # 加载所需程序集 Add-Type -AssemblyName System.IO.Compression Add-Type -AssemblyName System.IO.Compression.FileSystem Add-Type -AssemblyName System.Net.Mail # 替换为你的SMTP配置 $smtp = @{ from = "sender@example.com" to = "recipient@example.com" subject = "日志报告压缩包" body = "请查收附件中的日志报告" server = "smtp.example.com" } # --- 创建内存流并处理Zip压缩 --- $memoryStream = New-Object System.IO.MemoryStream try { # 用using块自动管理ZipArchive,确保关闭时完成压缩 using ($zipArchive = New-Object System.IO.Compression.ZipArchive($memoryStream, [System.IO.Compression.ZipArchiveMode]::Create, $true)) { # 创建Zip条目,指定压缩级别 $htmlEntry = $zipArchive.CreateEntry("log.html", [System.IO.Compression.CompressionLevel]::Optimal) # 写入内容到Zip条目 using ($entryStream = $htmlEntry.Open()) { using ($streamWriter = New-Object System.IO.StreamWriter($entryStream, [System.Text.Encoding]::UTF8)) { $streamWriter.Write($strTextToZip) $streamWriter.Flush() # 显式刷新确保内容全部写入 } } } # --- 关键:重置内存流位置到开头 --- $memoryStream.Seek(0, [System.IO.SeekOrigin]::Begin) | Out-Null # --- 创建并发送邮件 --- using ($msg = New-Object System.Net.Mail.MailMessage($smtp['from'], $smtp['to'], $smtp['subject'], $smtp['body'])) { $msg.IsBodyHTML = $true # 添加Zip附件,指定文件名和MIME类型 $attachment = New-Object System.Net.Mail.Attachment($memoryStream, "log.zip", "application/zip") $msg.Attachments.Add($attachment) # 发送邮件(如需认证,取消注释下面两行) using ($smtpClient = New-Object System.Net.Mail.SmtpClient($smtp['server'])) { # $smtpClient.Credentials = New-Object System.Net.NetworkCredential("你的用户名", "你的密码") # $smtpClient.EnableSsl = $true $smtpClient.Send($msg) } } } finally { # 释放内存流资源 $memoryStream.Dispose() }
关键修复点说明
- ZipArchive生命周期管理:用
using块包裹ZipArchive,确保其正确关闭,完成压缩数据的最终写入 - 流位置重置:关闭ZipArchive后必须重置
MemoryStream位置,否则邮件客户端无法读取到压缩内容 - 附件参数规范:指定附件文件名和MIME类型,保证收件端能正确识别并打开压缩包
- 自动资源释放:所有流、邮件对象均用
using块管理,避免内存泄漏和资源未释放问题
内容的提问来源于stack exchange,提问作者Tony
相关产品推荐
相关产品推荐

