从 VB 代码通过电子邮件将多个范围作为附件发送

Posted

技术标签:

【中文标题】从 VB 代码通过电子邮件将多个范围作为附件发送【英文标题】:Emailing multiple ranges as attachments from VB code 【发布时间】:2022-01-02 06:26:58 【问题描述】:

我使用来自 Internet 的一些标准代码来使用一个按钮在 Outlook 中创建一封电子邮件,其附件是工作表中按下该按钮的区域。代码运行良好。 如何扩展代码以附加两个或更多范围?在下面的代码中,我已经开始初始化第二个 Source 和 Dest,但随后对如何处理失去信心应用。

Private Sub CommandButton2_Click()

    Dim Source As Range
    Dim Source2 As Range
    Dim Dest As Workbook
    Dim Dest2 As Workbook
    Dim wb As Workbook
    Dim TempFilePath As String
    Dim TempFileName As String
    Dim FileExtStr As String
    Dim AutoPrint As String
    Dim FileFormatNum As Long
    Dim OutApp As Object
    Dim OutMail As Object

    Set Source = Nothing
    Set Source2 = Nothing
    On Error Resume Next
    Set Source = Range("A1:M47").SpecialCells(xlCellTypeVisible)
    Set Source2 = Range("AB1:AN47").SpecialCells(xlCellTypeVisible)
    On Error GoTo 0

    If Source Is Nothing Then
        MsgBox "The source is not a range or the sheet is protected, please correct and try again.", vbOKOnly
        Exit Sub
    End If

    With Application
        .ScreenUpdating = False
        .EnableEvents = False
    End With

    Set wb = ActiveWorkbook
    Set Dest = Workbooks.Add(xlWBATWorksheet)
    Set Dest2 = Workbooks.Add(xlWBATWorksheet)

    Source.Copy
    With Dest.Sheets(1)
        .Cells(1).PasteSpecial Paste:=8
        .Cells(1).PasteSpecial Paste:=xlPasteValues
        .Cells(1).PasteSpecial Paste:=xlPasteFormats
        .Cells(1).Select
        Application.CutCopyMode = False
    End With
    
    If Range("AC6") <> "" Then
    Source2.Copy
    With Dest2.Sheets(1)
        .Cells(1).PasteSpecial Paste:=8
        .Cells(1).PasteSpecial Paste:=xlPasteValues
        .Cells(1).PasteSpecial Paste:=xlPasteFormats
        .Cells(1).Select
        Application.CutCopyMode = False
    End With
    End If

    TempFilePath = Environ$("temp") & "\"
    TempFileName = "Selection of " & wb.Name & " " & Format(Now, "dd-mmm-yy h-mm-ss")

    If Val(Application.Version) < 12 Then
        'You use Excel 97-2003
        FileExtStr = ".xls": FileFormatNum = -4143
    Else
        'You use Excel 2007-2016
        FileExtStr = ".xlsx": FileFormatNum = 51
    End If

    Set OutApp = CreateObject("Outlook.Application")
    Set OutMail = OutApp.CreateItem(0)
    AutoPrint = Range("Y6").Value

    With Dest
        .SaveAs TempFilePath & TempFileName & FileExtStr, FileFormat:=FileFormatNum
        On Error Resume Next
        With OutMail
            .to = Range("S6").Value
            .CC = Range("S3").Value
            If Range("T3").Value = "Enter bcc addresses manually here" Then
            .bcc = ""
            Else
            .bcc = Range("T3").Value
            End If
            .Subject = Range("V6").Value
            .Body = Range("U6").Value
            .Attachments.Add Dest.FullName
            'You can add other files also like this
            '.Attachments.Add ("C:\test.txt")
            If AutoPrint = "Yes" Then
            .Send   'or use .Display
            Else
            .Display
            End If
        End With
        On Error GoTo 0
        .Close savechanges:=False
    End With

    Kill TempFilePath & TempFileName & FileExtStr

    Set OutMail = Nothing
    Set OutApp = Nothing

    With Application
        .ScreenUpdating = True
        .EnableEvents = True
    End With

End Sub

【问题讨论】:

这里的“最佳”方法是将创建新文件的代码从提供的范围提取到一个单独的方法中,因此如果需要,您可以多次调用它。如果将该方法设为函数,它可以返回临时文件的完整路径。 【参考方案1】:

根据我上面的评论:

Private Sub CommandButton2_Click()
    Dim OutApp As Object, AutoPrint
    Dim colAttachments As New Collection, fPath As String, ws As Worksheet, tm, p
    
    Set ws = ActiveSheet
    tm = Format(Now, "dd-mmm-yy h-mm-ss")
    
    'first attachment
    fPath = CreateAttachment(ws.Range("A1:M47"), _
                            "Selection1 of " & ws.Parent.Name & " " & tm)
    If Len(fPath) = 0 Then Exit Sub 'exit if there was a problem
    colAttachments.Add fPath
    
    If ws.Range("AC6") <> "" Then    'second attachment? Note the filename needs to be distinct...
        fPath = CreateAttachment(ws.Range("AB1:AN47"), _
                                 "Selection2 of " & ws.Parent.Name & " " & tm)
        If Len(fPath) = 0 Then Exit Sub 'exit if there was a problem
        colAttachments.Add fPath
    End If
        
    Set OutApp = CreateObject("Outlook.Application")
    AutoPrint = ws.Range("Y6").Value
    With OutApp.CreateItem(0)
        .to = ws.Range("S6").Value
        .CC = ws.Range("S3").Value
        If ws.Range("T3").Value = "Enter bcc addresses manually here" Then
            .bcc = ""
        Else
            .bcc = ws.Range("T3").Value
        End If
        .Subject = ws.Range("V6").Value
        .Body = ws.Range("U6").Value
        For Each p In colAttachments  'add each attachment from the collection
            .Attachments.Add p
            Kill p
        Next p
        If AutoPrint = "Yes" Then
            .Send
        Else
            .Display
        End If
    End With
      
End Sub

'create a file from the visible cells in `rng`
'  and return the path to the file
Function CreateAttachment(rng As Range, fName As String) As String
    Dim rngVis As Range, ws As Worksheet, ext, fPath As String
    'try to get a range with only visible cells
    On Error Resume Next
    Set rngVis = rng.SpecialCells(xlCellTypeVisible)
    On Error GoTo 0
    
    If rngVis Is Nothing Then
        MsgBox "The source is not a range or the sheet is protected. " & _
        "Please correct and try again.", vbExclamation + vbOKOnly
    Else
        Application.ScreenUpdating = False
        Set ws = Workbooks.Add(xlWBATWorksheet).Sheets(1)
        rngVis.Copy
        With ws.Cells(1)
            .PasteSpecial Paste:=xlPasteColumnWidths '8
            .PasteSpecial Paste:=xlPasteValues
            .PasteSpecial Paste:=xlPasteFormats
            .Select
        End With
        Application.CutCopyMode = False
        ext = IIf(Val(Application.Version) < 12, ".xls", ".xlsx")
        fPath = Environ$("temp") & "\" & fName & ext
        ws.Parent.SaveAs fPath
        ws.Parent.Close False
        CreateAttachment = fPath
    End If
End Function

【讨论】:

非常感谢您在回答中提供如此详细的信息。真正基本的问题:我试图将此代码附加到 ActiveX 按钮,并且代码似乎在函数开始时翻倒了。我是否认为该按钮仅识别 Private Sub/End Sub 代码,并且我需要以某种方式将 Function 组合到其中?在这一点上,我无法判断代码是否工作...... 函数是从CommandButton2_Click调用的,所以你的按钮只需要调用那个Sub 仅供参考,“跌倒”不是很具有描述性 - 如果您遇到代码问题,它总是有助于准确描述正在发生的事情。如果出现错误,错误消息是什么?如果单击“调试”,则会突出显示哪一行? 如果我运行调试,临时文件名会创建得很好,然后我会收到运行时错误“-2147417856 (80010100)”:自动化错误系统调用失败。当我收到此错误时,我没有看到突出显示的行。这在某种程度上与定义了三个单独的命令按钮这一事实有关吗? 我只创建一个附件的原始代码位于 CommandButton2 上,我将您的代码(进行了一些非常简单的更改)放在了 CommandButton3 上。

以上是关于从 VB 代码通过电子邮件将多个范围作为附件发送的主要内容,如果未能解决你的问题,请参考以下文章

我可以通过自动电子邮件从 Google 表单/Google 表格发送多个上传的附件吗?

vbscript [.net] [vb]从内存流发送包含附件的电子邮件

vbscript [.net] [vb]从目录发送带有文件附件的电子邮件

将包含代码的 Excel 文件作为附件发送

android导出到csv并作为电子邮件附件发送

sendmailR(第 2 部分):将文件作为邮件附件发送