简体   繁体   English

Excel 宏 VBA - Email 发送

[英]Excel Macro VBA - Email sending

I am having trouble figuring out why my program is not running as intended.我无法弄清楚为什么我的程序没有按预期运行。 Once the macro begins, it runs all line items in the spreadsheet instead of the ones I specified.宏开始后,它将运行电子表格中的所有行项目,而不是我指定的行项目。 The purpose of the program is to send emails to the correct person and append any additional rows with their name.该程序的目的是将电子邮件发送给正确的人和 append 任何带有其姓名的其他行。 For each unique email I am collecting all of the data and sending it.对于每个独特的 email,我正在收集所有数据并将其发送。 Any help would be greatly appreciated.任何帮助将不胜感激。 I have worked with other people and they have made edits but no solutions.我曾与其他人一起工作,他们进行了编辑,但没有解决方案。 Due to the sensitive nature of the source data I included an image of the column header.由于源数据的敏感性,我包含了 header 列的图像。 Code to follow, thank you.代码遵循,谢谢。

Column Headers列标题

Option Explicit
Sub Send()
    Dim rEmailAddr As Range, rCell As Range, rNext As Range
    Dim NmeRow As Long, x As Long
    Dim MailTo As String, MailSubject As String, MailBody As String, AddRow As String, tableHdr As String, MsgStr As String
    Dim OutApp As Object, OutMail As Object
    Dim CurrentEmail As String, LastEmail As String
    
    If OutApp Is Nothing Then
        'Outlook is not opened, so open
        Set OutApp = CreateObject("Outlook.Application")
    End If
    
    'Set email address as range for first loop to run down
    Set rEmailAddr = Range(Range("D2"), Range("D" & Rows.Count).End(xlUp))
    
    'MailSubject does not change, so only needs to be created once
    MailSubject = "Action and Response Requested - Reserve Review for Claim(s)"
    
    'Get a row count to clear column AM at the end
     x = rEmailAddr.Rows.Count
     
    'Create the html table and header from the first row
     tableHdr = "<table border=1><tr><th>" & Range("G1").Value & "</th>" _
         & "<th>" & Range("H1").Value & "</th>" _
         & "<th>" & Range("I1").Value & "</th>" _
         & "<th>" & Range("J1").Value & "</th>" _
         & "<th>" & Range("K1").Value & "</th>" _
         & "<th>" & Range("L1").Value & "</th>" _
         & "<th>" & Range("M1").Value & "</th>" _
         & "<th>" & Range("N1").Value & "</th>" _
         & "<th>" & Range("O1").Value & "</th>" _
         & "<th>" & Range("P1").Value & "</th>" _
         & "<th>" & Range("T1").Value & "</th>" _
         & "<th>" & Range("U1").Value & "</th>" _
         & "<th>" & Range("V1").Value & "</th>" _
         & "<th>" & Range("W1").Value & "</th>" _
         & "<th>" & Range("X1").Value & "</th>" _
         & "<th>" & Range("Y1").Value & "</th>" _
         & "<th>" & Range("Z1").Value & "</th>" _
         & "<th>" & Range("AA1").Value & "</th>" _
         & "<th>" & Range("AB1").Value & "</th>" _
         & "<th>" & Range("AC1").Value & "</th>" _
         & "<th>" & Range("AD1").Value & "</th>" _
         
    'Check to see if column Q = 'yes' and skip mail if it does
    CurrentEmail = ""
    LastEmail = ""
    
    For Each rCell In rEmailAddr
        CurrentEmail = Replace(rCell.Value, " ", "")
        If ((rCell.Value <> "") And CurrentEmail <> LastEmail) Then
                NmeRow = rCell.Row
                MailTo = rCell.Value 'column D
                
                'Create MailBody table row for first row
                MailBody = "<tr>" _
                        & "<td>" & (rCell.Offset(0, 3).Value) & "</td>" _
                        & "<td>" & (rCell.Offset(0, 4).Value) & "</td>" _
                        & "<td>" & (rCell.Offset(0, 5).Value) & "</td>" _
                        & "<td>" & (rCell.Offset(0, 6).Value) & "</td>" _
                        & "<td>" & (rCell.Offset(0, 7).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 8).Value) & "</td>" _
                        & "<td>" & (rCell.Offset(0, 9).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 10).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 11).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 12).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 16).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 17).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 18).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 19).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 20).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 21).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 22).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 23).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 24).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 25).Value) & "</td>" _
                        & "<td>" & CStr(rCell.Offset(0, 26).Value) & "</td>" _
                        & "</tr>"
                        
                'Second loop checks the email addresses of all cells following the current cell in the first loop.
                'Yes will be appended on any duplicate finds and another row added to the mailbody table
                For Each rNext In rEmailAddr.Offset(NmeRow - 1, 0).Resize(x - NmeRow) 'process to last row only
                
                   If Replace(rNext.Value, " ", "") = Replace(rCell.Value, " ", "") Then
                   
                        'Create additional table row for each extra row found"
                        AddRow = "<tr>" _
                                & "<td>" & CStr(rNext.Offset(0, 3).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 4).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 5).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 6).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 7).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 8).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 9).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 10).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 11).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 12).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 16).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 17).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 18).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 19).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 20).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 21).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 22).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 23).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 24).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 25).Value) & "</td>" _
                                & "<td>" & CStr(rNext.Offset(0, 26).Value) & "</td>" _
                                            & "</tr>"
                              MailBody = MailBody & AddRow
                    End If
                    
                   'Clear additional table row variable ready for next
                Next rNext
                
                'Create email
                Set OutMail = OutApp.createitem(0)
                With OutMail
                     .to = Replace(MailTo, " ", "")
                     .Subject = MailSubject
                     .HTMLBody = tableHdr & MailBody & "</table>"
                     .Display
                End With
                
                LastEmail = Replace(rCell.Value, " ", "")
        End If
         
    Next rCell
End Sub



Use a dictionary (using email address as key) to group the rows for each email with a single pass down the sheet.使用字典(使用 email 地址作为键)对每个 email 的行进行分组,只需向下传递一次。 Then loop through the dictionary keys creating each email from the rows number held as a comma separated list in the dictionary value.然后遍历字典键,从字典值中以逗号分隔的列表保存的行号创建每个 email。

Option Explicit

Sub Send()

    Dim OutApp As Object, OutMail As Object
    Dim sEmailAddr As String, tableHdr As String
    Dim MailTo As String, Mailbody As String, MailSubject As String
    
    Dim wb As Workbook, ws As Worksheet
    Dim lastRow As Long, n As Long, i As Long
    Dim k, v, arData
    
    Dim dict As Object, fso As Object, ts As Object
    Set dict = CreateObject("Scripting.Dictionary")
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    Set wb = ThisWorkbook
    Set ws = wb.Sheets(1) ' change to suit
    
    ' put data into an array
    With ws
        lastRow = .Range("D" & Rows.Count).End(xlUp).Row
        arData = .Range("A1:AD" & lastRow)
    End With
    
    ' compile list of rows for each address using dictionary
    ' key = address, value = comma separated list of rows
    For i = 2 To UBound(arData)
        sEmailAddr = Trim(arData(i, 4)) ' col D
        sEmailAddr = Replace(sEmailAddr, " ", "")
        
        ' build list of rows for each email address
        If dict.exists(sEmailAddr) Then
            dict(sEmailAddr) = dict(sEmailAddr) & "," & i
        Else
            dict.Add sEmailAddr, i
        End If
    Next
    
    'Create the html table and header from the first row
    'G - P, T - AD
    tableHdr = "<table border=""1"" cellspacing=""0"" cellpadding=""3""><tr>"
    For n = 7 To 30
        Select Case n
            Case 7 To 16, 20 To 30
                tableHdr = tableHdr & "<th>" & arData(1, n) & "</th>"
        End Select
    Next
    tableHdr = tableHdr & "</tr>" & vbCr
        
    'If OutApp Is Nothing Then
        'Outlook is not opened, so open
    '    Set OutApp = CreateObject("Outlook.Application")
    'End If
    
     'MailSubject does not change, so only needs to be created once
    MailSubject = "Action and Response Requested - Reserve Review for Claim(s)"
       
    ' send emails
    For Each k In dict.keys
         MailTo = k
         MailBody = ""
         
         ' loop through rows for this email
         For Each v In Split(dict(k), ",")
         
            Mailbody = Mailbody & "<tr>" & vbCr
            For n = 7 To 30
               Select Case n
                    Case 7 To 11, 13
                        Mailbody = Mailbody & "<td>" & arData(v, n) & "</td>"
                    Case 12, 14 To 16, 20 To 30
                        Mailbody = Mailbody & "<td>" & CStr(arData(v, n)) & "</td>"
               End Select
            Next
            Mailbody = Mailbody & "</tr>" & vbCr
                      
        Next
        
        ' dump text to file to check without outlook
        Set ts = fso.createTextFile(wb.Path & "\" & MailTo & ".html", True)
        ts.writeLine "To : " & MailTo & "<br/>"
        ts.writeLine "Subject: " & MailSubject & "<br/>"
        ts.write tableHdr & Mailbody & "</table>"
        ts.Close
        
        'Create email
        'Set OutMail = OutApp.createitem(0)
        'With OutMail
        '    .To = Replace(MailTo, " ", "")
        '    .Subject = MailSubject
        '    .HTMLBody = tableHdr & Mailbody & "</table>"
        '    .Display
        'End With
          
    Next
    MsgBox dict.Count & " emails sent"
End Sub

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM