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

通过Excel宏批量生成Outlook邮件时程序崩溃问题求助

问题:批量生成Outlook邮件时因窗口过多导致崩溃

我用社区协助编写的VBA宏从Excel提取数据生成Outlook邮件,因为需要检查内容后再发送,所以用了.Display而不是.Send。但处理超过100条记录时,Outlook会打开大量邮件窗口,随后崩溃关闭。


原代码

邮件生成与HTML转换模块

Option Explicit

Sub Mail_Workbook(ToString As String, SubjectString As String, BodyString As String, _
  Optional CCString As String, Optional BCCString As String, Optional AttachmentName As String)
    Dim OutApp As Object
    Dim OutMail As Object
    Set OutApp = CreateObject("Outlook.Application")
    Set OutMail = OutApp.CreateItem(0)
    On Error Resume Next
    ' Change the mail address and subject in the macro before you run it.
    With OutMail
        .SentOnBehalfOfName = "kontakt@xxx.pl"
        .To = ToString
        If CCString <> "" Then
            .CC = CCString
        End If
        If BCCString <> "" Then
            .BCC = BCCString
        End If
        .Subject = SubjectString
        .HTMLBody = BodyString
        If AttachmentName <> "" Then
            .Attachments.Add (AttachmentName)
        End If
        'Choose either Send or Display
        '.Send
        .Display
    End With
    On Error GoTo 0

    Set OutMail = Nothing
    Set OutApp = Nothing
End Sub

Function RangetoHTML(rng As Range)
Dim fso As Object
Dim ts As Object
Dim TempFile As String
Dim TempWB As Workbook

TempFile = ThisWorkbook.Path & "\" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"

'Copy the range and create a new workbook to past the data in
rng.Copy
Set TempWB = Workbooks.Add(1)
With TempWB.Sheets(1)
    .Cells(1).PasteSpecial Paste:=8
    .Cells(1).PasteSpecial xlPasteValues, , False, False
    .Cells(1).PasteSpecial xlPasteFormats, , False, False
    .Cells(1).Select
    Application.CutCopyMode = False
    On Error Resume Next
    .DrawingObjects.Visible = True
    .DrawingObjects.Delete
    On Error GoTo 0
End With

'Publish the sheet to a htm file
With TempWB.PublishObjects.Add( _
    SourceType:=xlSourceRange, _
    Filename:=TempFile, _
    Sheet:=TempWB.Sheets(1).Name, _
    Source:=TempWB.Sheets(1).UsedRange.Address, _
    HtmlType:=xlHtmlStatic)
    .Publish (True)
End With

'Read all data from the htm file into RangetoHTML
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
RangetoHTML = ts.readall
ts.Close
RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", "align=left x:publishsource=")

'Close TempWB
TempWB.Close savechanges:=False

'Delete the htm file we used in this function
Kill TempFile

Set ts = Nothing
Set fso = Nothing
Set TempWB = Nothing
End Function

主执行宏

Option Explicit

Sub SendNewMails()

    Dim clE As Range
    Dim shtA As Worksheet

    Set shtA = Sheets("MAKRO")
    Dim SubjectString As String
    SubjectString = Range("Mail_Subject")
   
    For Each clE In Range("Table1[mail]")
        Dim ToString As String
        ToString = clE.Value
        Dim BodyString As String
        BodyString = shtA.Cells(clE.Row, "J")
        Mail_Workbook ToString, SubjectString, BodyString
    Next
End Sub

解决方案

方案1:复用Outlook应用实例

原代码每次生成邮件都新建Outlook实例,会大幅占用系统资源。修改为全局复用一个实例:

修改后的邮件生成函数

Option Explicit

Sub Mail_Workbook(OutApp As Object, ToString As String, SubjectString As String, BodyString As String, _
  Optional CCString As String, Optional BCCString As String, Optional AttachmentName As String)
    Dim OutMail As Object
    Set OutMail = OutApp.CreateItem(0)
    On Error Resume Next
    With OutMail
        .SentOnBehalfOfName = "kontakt@xxx.pl"
        .To = ToString
        If CCString <> "" Then
            .CC = CCString
        End If
        If BCCString <> "" Then
            .BCC = BCCString
        End If
        .Subject = SubjectString
        .HTMLBody = BodyString
        If AttachmentName <> "" Then
            .Attachments.Add (AttachmentName)
        End If
        .Display
    End With
    On Error GoTo 0
    Set OutMail = Nothing
End Sub

' RangetoHTML函数保持不变
Function RangetoHTML(rng As Range)
Dim fso As Object
Dim ts As Object
Dim TempFile As String
Dim TempWB As Workbook

TempFile = ThisWorkbook.Path & "\" & Format(Now, "dd-mm-yy h-mm-ss") & ".htm"

rng.Copy
Set TempWB = Workbooks.Add(1)
With TempWB.Sheets(1)
    .Cells(1).PasteSpecial Paste:=8
    .Cells(1).PasteSpecial xlPasteValues, , False, False
    .Cells(1).PasteSpecial xlPasteFormats, , False, False
    .Cells(1).Select
    Application.CutCopyMode = False
    On Error Resume Next
    .DrawingObjects.Visible = True
    .DrawingObjects.Delete
    On Error GoTo 0
End With

With TempWB.PublishObjects.Add( _
    SourceType:=xlSourceRange, _
    Filename:=TempFile, _
    Sheet:=TempWB.Sheets(1).Name, _
    Source:=TempWB.Sheets(1).UsedRange.Address, _
    HtmlType:=xlHtmlStatic)
    .Publish (True)
End With

Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(TempFile).OpenAsTextStream(1, -2)
RangetoHTML = ts.readall
ts.Close
RangetoHTML = Replace(RangetoHTML, "align=center x:publishsource=", "align=left x:publishsource=")

TempWB.Close savechanges:=False
Kill TempFile

Set ts = Nothing
Set fso = Nothing
Set TempWB = Nothing
End Function

修改后的主执行宏

Option Explicit

Sub SendNewMails()
    Dim clE As Range
    Dim shtA As Worksheet
    Dim OutApp As Object
    Dim SubjectString As String

    Set shtA = Sheets("MAKRO")
    SubjectString = Range("Mail_Subject")
    
    ' 仅创建一次Outlook实例
    Set OutApp = CreateObject("Outlook.Application")
    
    For Each clE In Range("Table1[mail]")
        Dim ToString As String
        ToString = clE.Value
        Dim BodyString As String
        BodyString = shtA.Cells(clE.Row, "J")
        Mail_Workbook OutApp, ToString, SubjectString, BodyString
    Next
    
    Set OutApp = Nothing
End Sub

方案2:分批生成邮件

设置每生成固定数量的邮件后暂停,等待用户处理现有窗口再继续:

Option Explicit

Sub SendNewMails()
    Dim clE As Range
    Dim shtA As Worksheet
    Dim OutApp As Object
    Dim SubjectString As String
    Dim counter As Integer
    Dim batchSize As Integer
    
    batchSize = 20 ' 每批生成20封邮件
    counter = 0
    
    Set shtA = Sheets("MAKRO")
    SubjectString = Range("Mail_Subject")
    Set OutApp = CreateObject("Outlook.Application")
    
    For Each clE In Range("Table1[mail]")
        counter = counter + 1
        Dim ToString As String
        ToString = clE.Value
        Dim BodyString As String
        BodyString = shtA.Cells(clE.Row, "J")
        Mail_Workbook OutApp, ToString, SubjectString, BodyString
        
        ' 达到批次数量时提示用户处理
        If counter Mod batchSize = 0 Then
            MsgBox "已生成" & counter & "封邮件,请处理后点击确定继续", vbInformation
        End If
    Next
    
    MsgBox "邮件生成完成,共生成" & counter & "封邮件", vbInformation
    Set OutApp = Nothing
End Sub

方案3:先存草稿再统一检查

如果不需要即时打开窗口,可将邮件保存到草稿箱,之后在Outlook中批量检查:
修改Mail_Workbook中的.Display为.Save即可:

' 替换原代码中的.Display
.Save

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:55:01