You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET中生成的PDF无法作为邮件附件添加的问题排查

解决PDF生成后作为邮件附件添加时提示文件找不到的问题

我之前也碰到过一模一样的情况:明明PDF已经生成,能打开能查看,但一添加成邮件附件就报FileNotFoundException,路径文件名都对但就是找不到。结合你的代码和报错信息,问题肯定是PDF文件被打印进程占用了——Print()方法执行后,后台的打印服务可能还没完全释放文件句柄,导致邮件程序无法读取这个文件。

先再明确下你的场景:

  • 能成功生成PDF到C:\TEMP\目录
  • 可正常打开该PDF文件
  • 邮件添加附件时抛出'System.IO.FileNotFoundException' in mscorlib.dll,提示找不到目标PDF

你的PDF生成代码(可正常运行)

Dim txtVarFile As String
Dim txtVarEmail As String = "test@test.com"
Dim txtVarPasss As String = "password"
Dim txtVarSMTP As String = "smtp.gmail.com"
Dim intVarPort As Integer = 587
Dim txtVarDescription As String
'Create Invoice and Save as pdf document
txtVarFile = "C:\TEMP\" & strClientNum & "_" & strInvNum & ".pdf"
PageSetupDialog1.Document = PrintDocument1
PageSetupDialog1.PrinterSettings.DefaultPageSettings.Landscape = True
prtFrmInvoice.PrinterSettings = PageSetupDialog1.PrinterSettings
If prtFrmInvoice.PrinterSettings.IsValid Then
prtFrmInvoice.PrinterSettings.PrinterName = "Microsoft Print to PDF"
prtFrmInvoice.PrintFileName = txtVarFile
prtFrmInvoice.PrintAction = Printing.PrintAction.PrintToFile
prtFrmInvoice.Print()
End If

你的邮件发送代码(添加附件失败)

'Send copy of Invoice per Email
Try
Dim SmtpServer As New SmtpClient()
Dim eMail As New MailMessage()
'Dim attachment As System.Net.Mail.Attachment
LogFile.Refresh()
SmtpServer.UseDefaultCredentials = False
SmtpServer.Credentials = New Net.NetworkCredential(txtVarEmail, txtVarPasss)
SmtpServer.Port = intVarPort
SmtpServer.EnableSsl = True
SmtpServer.Host = txtVarSMTP
eMail = New MailMessage()
eMail.From = New MailAddress(txtVarEmail)
eMail.To.Add(strClientEmail)
eMail.Subject = "AltHealth Invoice"
eMail.Body = "Please find your latest invoice attached"
'attachment = New System.Net.Mail.Attachment(txtVarFile)
'eMail.Attachments.Add(attachment)
eMail.Attachments.Add(New Attachment(txtVarFile))
SmtpServer.Send(eMail)
MsgBox("The Invoice has been sent sucessfully via email - File: " & txtVarFile)
Catch ex As Exception
MsgBox("Send failure: " & ex.ToString())
End Try

解决方案:确保文件生成后完全就绪且未被占用

方案1:等待文件解锁后再发送邮件

写一个辅助函数检测文件是否可以被读写(即未被占用),然后在生成PDF后循环等待,直到文件可用:

' 导入System.IO和System.Threading命名空间
Private Function IsFileAvailable(filePath As String) As Boolean
    Try
        ' 尝试以独占方式打开文件,能打开说明未被占用
        Using fs As FileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
            Return True
        End Using
    Catch ex As IOException
        ' 文件被占用,返回False
        Return False
    End Try
End Function

然后在prtFrmInvoice.Print()之后添加等待逻辑:

prtFrmInvoice.Print()
' 等待文件解锁
Do While Not IsFileAvailable(txtVarFile)
    Thread.Sleep(500) ' 每500毫秒检查一次,可根据情况调整
Loop
' 这里再执行邮件发送代码

方案2:手动释放打印对象资源

如果prtFrmInvoice后续不再使用,可以在打印完成后直接释放它的资源,强制关闭文件句柄:

prtFrmInvoice.Print()
prtFrmInvoice.Dispose() ' 释放打印窗体/对象的资源,确保文件被解锁

⚠️ 注意:如果之后还要用到prtFrmInvoice,不要调用Dispose(),否则会导致对象不可用。

方案3:检查文件写入是否完成

有时候Print()方法执行完毕,但文件还在后台写入,也会导致读取失败。可以通过检查文件大小是否稳定来判断写入完成:

prtFrmInvoice.Print()
Dim prevFileSize As Long = -1
Dim fileInfo As New FileInfo(txtVarFile)
Do
    If fileInfo.Exists Then
        If fileInfo.Length = prevFileSize Then
            Exit Do ' 文件大小稳定,说明写入完成
        End If
        prevFileSize = fileInfo.Length
    End If
    Thread.Sleep(300)
Loop

修改后的完整流程示例

把等待逻辑插入到PDF生成和邮件发送之间,确保文件完全可用:

' 先生成PDF(你的原代码)
txtVarFile = "C:\TEMP\" & strClientNum & "_" & strInvNum & ".pdf"
PageSetupDialog1.Document = PrintDocument1
PageSetupDialog1.PrinterSettings.DefaultPageSettings.Landscape = True
prtFrmInvoice.PrinterSettings = PageSetupDialog1.PrinterSettings
If prtFrmInvoice.PrinterSettings.IsValid Then
prtFrmInvoice.PrinterSettings.PrinterName = "Microsoft Print to PDF"
prtFrmInvoice.PrintFileName = txtVarFile
prtFrmInvoice.PrintAction = Printing.PrintAction.PrintToFile
prtFrmInvoice.Print()
End If

' 添加等待文件可用的逻辑
Do While Not IsFileAvailable(txtVarFile)
    Thread.Sleep(500)
Loop

' 再执行邮件发送(你的原代码)
Try
Dim SmtpServer As New SmtpClient()
Dim eMail As New MailMessage()
LogFile.Refresh()
SmtpServer.UseDefaultCredentials = False
SmtpServer.Credentials = New Net.NetworkCredential(txtVarEmail, txtVarPasss)
SmtpServer.Port = intVarPort
SmtpServer.EnableSsl = True
SmtpServer.Host = txtVarSMTP
eMail = New MailMessage()
eMail.From = New MailAddress(txtVarEmail)
eMail.To.Add(strClientEmail)
eMail.Subject = "AltHealth Invoice"
eMail.Body = "Please find your latest invoice attached"
eMail.Attachments.Add(New Attachment(txtVarFile))
SmtpServer.Send(eMail)
MsgBox("The Invoice has been sent sucessfully via email - File: " & txtVarFile)
Catch ex As Exception
MsgBox("Send failure: " & ex.ToString())
End Try

这个问题的核心就是文件生成后没有完全就绪,被后台进程占用了。用上面的方法确保文件可以被正常读取后,邮件添加附件的问题就能解决了。

内容的提问来源于stack exchange,提问作者AquaAlex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 19:42:41