VBA to eMail (Outlook) Worksheets Individually

Small Paul

Board Regular
Joined
Jun 28, 2018
Messages
118
Hi

I have a workbook with a set of data which needs to emailed to a variety of recipients on a daily basis.
I have a macro which searches for a 'unique' value on each row and sets up (and names) a new worksheet for each.

Each worksheet then needs to be emailed, using outlook, to the individual whose email address is in cell B2. I have found the following macro online but cannot get it to work.

Code:
Mail_Worksheets_TEST Macro'
    Dim sh As Worksheet
    Dim wb As Workbook
    Dim FileExtStr As String
    Dim FileFormatNum As Long
    Dim TempFilePath As String
    Dim TempFileName As String
    Dim OutApp As Object
    Dim OutMail As Object


    TempFilePath = Environ$("temp") & "\"


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


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


    Set OutApp = CreateObject("Outlook.Application")


    For Each sh In ThisWorkbook.Worksheets
        If sh.Range("B2").Value Like "?*@?*.?*" Then


            sh.Copy
            Set wb = ActiveWorkbook


            TempFileName = "Sheet " & sh.Name & " of " _
                         & ThisWorkbook.Name & " " & Format(Now, "dd-mmm-yy h-mm-ss")


            Set OutMail = OutApp.CreateItem(0)


            With wb
                .SaveAs TempFilePath & TempFileName & FileExtStr, FileFormat:=FileFormatNum


                On Error Resume Next
                With OutMail
                    .to = sh.Range("B2").Value
                    .CC = ""
                    .BCC = ""
                    .Subject = "IGNORE - Just Testing"
                    .Body = "Cymru Rule"
                    .Send   'or use .Display
                End With
                On Error GoTo 0


                .Close savechanges:=False
            End With
            
            Set OutMail = Nothing


            Kill TempFilePath & TempFileName & FileExtStr


        End If
    Next sh


    Set OutApp = Nothing


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

The macro runs through without an 'error' but no email is received.

Can anybody please help?

Many thanks
Small Paul.
 

Excel Facts

Will the fill handle fill 1, 2, 3?
Yes! Type 1 in a cell. Hold down Ctrl while you drag the fill handle.
Where's the code that's creating the new worksheet?

Is that worksheet being created in the workbook the code is in or a new workbook?

That code is going through every worksheet in the workbook that the code is in and if it finds a valid email address in B2 on any of those worksheets it will create an email.
 
Upvote 0
Hi Norie
The workbook is a Salesforce download and the worksheet is named 'Master'. The first macro splits Master and adds a new worksheet in the same workbook. Code is:

Code:
' Split_SS_Into_Separate_Sheets_TEST Macro
'
 
    Dim My_Range As Range
    Dim FieldNum As Long
    Dim CalcMode As Long
    Dim ViewMode As Long
    Dim ws2 As Worksheet
    Dim Lrow As Long
    Dim cell As Range
    Dim CCount As Long
    Dim WSNew As Worksheet
    Dim ErrNum As Long
 
    Set My_Range = Range("A1:D" & LastRow(ActiveSheet))
    My_Range.Parent.Select
 
    If ActiveWorkbook.ProtectStructure = True Or _
       My_Range.Parent.ProtectContents = True Then
        MsgBox "Sorry, not working when the workbook or worksheet is protected", _
               vbOKOnly, "Copy to new worksheet"
        Exit Sub
    End If
 
    FieldNum = 1
 
    'Turn off AutoFilter
    My_Range.Parent.AutoFilterMode = False
 
    With Application
        CalcMode = .Calculation
        .Calculation = xlCalculationManual
        .ScreenUpdating = False
        .EnableEvents = False
    End With
    ViewMode = ActiveWindow.View
    ActiveWindow.View = xlNormalView
    ActiveSheet.DisplayPageBreaks = False
 
    Set ws2 = Worksheets.Add
 
    With ws2
        My_Range.Columns(FieldNum).AdvancedFilter _
                Action:=xlFilterCopy, _
                CopyToRange:=.Range("A1"), Unique:=True
 
        Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
        For Each cell In .Range("A2:A" & Lrow)
 
            My_Range.AutoFilter Field:=FieldNum, Criteria1:="=" & _
             Replace(Replace(Replace(cell.Value, "~", "~~"), "*", "~*"), "?", "~?")
 
            CCount = 0
            On Error Resume Next
            CCount = My_Range.Columns(1).SpecialCells(xlCellTypeVisible) _
                     .Areas(1).Cells.Count
            On Error GoTo 0
            If CCount = 0 Then
                MsgBox "There are more than 8192 areas for the value : " & cell.Value _
                     & vbNewLine & "It is not possible to copy the visible data." _
                     & vbNewLine & "Tip: Sort your data before you use this macro.", _
                       vbOKOnly, "Split in worksheets"
            Else
                Set WSNew = Worksheets.Add(After:=Sheets(Sheets.Count))
                On Error Resume Next
                WSNew.Name = cell.Value
                If Err.Number > 0 Then
                    ErrNum = ErrNum + 1
                    WSNew.Name = "Error_" & Format(ErrNum, "0000")
                    Err.Clear
                End If
                On Error GoTo 0
 
                My_Range.SpecialCells(xlCellTypeVisible).Copy
                With WSNew.Range("A1")
                    .PasteSpecial Paste:=8
                    .PasteSpecial xlPasteValues
                    .PasteSpecial xlPasteFormats
                    Application.CutCopyMode = False
                    .Select
                End With
            End If
 
            My_Range.AutoFilter Field:=FieldNum
 
        Next cell
 
        On Error Resume Next
        Application.DisplayAlerts = False
        .Delete
        Application.DisplayAlerts = True
        On Error GoTo 0
 
    End With
 
    My_Range.Parent.AutoFilterMode = False
 
    If ErrNum > 0 Then
        MsgBox "Rename every WorkSheet name that start with ""Error_"" manually" _
             & vbNewLine & "There are characters in the name that are not allowed" _
             & vbNewLine & "in a sheet name or the worksheet already exist."
    End If
 
    My_Range.Parent.Select
    ActiveWindow.View = ViewMode
    With Application
        .ScreenUpdating = True
        .EnableEvents = True
        .Calculation = CalcMode
    End With
 
End Sub

The macro I am struggling with is supposed to look at each worksheet, pick up the email address in B2 and send the worksheet in an Outlook email.
Cheers
Small Paul.
 
Upvote 0
The first code you posted definitely loops through all the worksheets, are you sure there are worksheets with valid email addresses in B2?
 
Upvote 0
Absolutely.
I am presently running a 'test' with the email addresses of myself and a few colleagues.
As I say:
The initial macro works perfectly
The 2nd (email) macro runs without error but does not send an email
 
Upvote 0
Have you stepped through the 2nd email macro to see what's happening?

PS This might sound daft but have you checked Outlook to see if there's anything in the Outbox or Drafts folders?
 
Upvote 0
Hi Norie

Many apologies, I am such a numpty! I had the macro in my Personal folder rather than within the spreadsheet. Obviously there was nothing to pick up!

All I have to do now is:
1) convert each sheet to pdf
2) NOT email the 'Master' worksheet
3) Identify a way of password protecting each email attachment

Many thanks for your help - it was your 'step-through' comment that got me there!

Cheers
Small Paul.
 
Upvote 0
Hi

I have a macro which, with the help of Norie, takes a table in the Master Sheet (IFA Trade Commission) and separates it using a unique identifier into individual worksheets.
As stated in Post #7 (point 2) I am having difficulty with the emailing in that I cannot omit the Master Sheet from emailing. As it holds all the information contained in the workbook I do not want this being emailed to the first email address. Can anybody please advise.

Cheers
Small Paul.
 
Upvote 0
Can you post the current code?
 
Upvote 0
Hi Norie

It is enormous but is stated below:

Code:
Sub Split_SS_Into_Separate_Sheets_TEST()
'
' Split_SS_Into_Separate_Sheets_TEST Macro
'
 
'Note: This macro use the function LastRow
    Dim My_Range As Range
    Dim FieldNum As Long
    Dim CalcMode As Long
    Dim ViewMode As Long
    Dim ws2 As Worksheet
    Dim Lrow As Long
    Dim cell As Range
    Dim CCount As Long
    Dim WSNew As Worksheet
    Dim ErrNum As Long
 
   
    ActiveWorkbook.SaveAs "Z:\Paul\IFA Trade Commission.xlsx"
    Columns("L:L").Select
    Selection.Insert Shift:=xlToRight
    Range("Table1[[#Headers],[Column1]]").Select
    ActiveCell.FormulaR1C1 = "Email"
    Range("L2").Select
    Workbooks.Open Filename:="Z:\Paul\IFA Contacts.xlsx"
    Windows("IFA Trade Commission").Activate
    ActiveCell.FormulaR1C1 = _
        "=VLOOKUP([@[Account Name]],'IFA Contacts.xlsx'!R2C1:R48C3,2,FALSE)"
    Columns("A:S").EntireColumn.AutoFit
    With Sheets("IFA Trade Commission")
   .Range("B1:B500", .Range("B1:B500").End(xlDown)).WrapText = True
   Columns("B").ColumnWidth = 30
 
  
    End With
 
    'Set filter range on ActiveSheet: A1 is the top left cell of your filter range
    'and the header of the first column, D is the last column in the filter range.
    'You can also add the sheet name to the code like this :
    'Worksheets("Sheet1").Range("A1:D" & LastRow(Worksheets("Sheet1")))
    'No need that the sheet is active then when you run the macro when you use this.
    Set My_Range = Range("A1:S" & LastRow(ActiveSheet))
    My_Range.Parent.Select
 
    If ActiveWorkbook.ProtectStructure = True Or _
       My_Range.Parent.ProtectContents = True Then
        MsgBox "Sorry, not working when the workbook or worksheet is protected", _
               vbOKOnly, "Copy to new worksheet"
        Exit Sub
    End If
 
    'This example filters on the first column in the range(change the field if needed)
    'In this case the range starts in A so Field:=1 is column A, 2 = column B, ......
    FieldNum = 11
 
    'Turn off AutoFilter
    My_Range.Parent.AutoFilterMode = False
 
    'Change ScreenUpdating, Calculation, EnableEvents, ....
    With Application
        CalcMode = .Calculation
        .Calculation = xlCalculationManual
        .ScreenUpdating = False
        .EnableEvents = False
    End With
    ViewMode = ActiveWindow.View
    ActiveWindow.View = xlNormalView
    ActiveSheet.DisplayPageBreaks = False
 
    'Add a worksheet to copy the a unique list and add the CriteriaRange
    Set ws2 = Worksheets.Add
 
    With ws2
        'first we copy the Unique data from the filter field to ws2
        My_Range.Columns(FieldNum).AdvancedFilter _
                Action:=xlFilterCopy, _
                CopyToRange:=.Range("A1"), Unique:=True
 
        'loop through the unique list in ws2 and filter/copy to a new sheet
        Lrow = .Cells(Rows.Count, "A").End(xlUp).Row
        For Each cell In .Range("A2:A" & Lrow)
 
            'Filter the range
            My_Range.AutoFilter Field:=FieldNum, Criteria1:="=" & _
             Replace(Replace(Replace(cell.Value, "~", "~~"), "*", "~*"), "?", "~?")
 
            'Check if there are no more then 8192 areas(limit of areas)
            CCount = 0
            On Error Resume Next
            CCount = My_Range.Columns(1).SpecialCells(xlCellTypeVisible) _
                     .Areas(1).Cells.Count
            On Error GoTo 0
            If CCount = 0 Then
                MsgBox "There are more than 8192 areas for the value : " & cell.Value _
                     & vbNewLine & "It is not possible to copy the visible data." _
                     & vbNewLine & "Tip: Sort your data before you use this macro.", _
                       vbOKOnly, "Split in worksheets"
            Else
                'Add a new worksheet
                Set WSNew = Worksheets.Add(After:=Sheets(Sheets.Count))
                On Error Resume Next
                WSNew.Name = cell.Value
                If Err.Number > 0 Then
                    ErrNum = ErrNum + 1
                    WSNew.Name = "Error_" & Format(ErrNum, "0000")
                    Err.Clear
                End If
                On Error GoTo 0
 
                'Copy the visible data to the new worksheet
                My_Range.SpecialCells(xlCellTypeVisible).Copy
                With WSNew.Range("A1")
                    ' Paste:=8 will copy the columnwidth in Excel 2000 and higher
                    ' Remove this line if you use Excel 97
                    .PasteSpecial Paste:=8
                    .PasteSpecial xlPasteValues
                    .PasteSpecial xlPasteFormats
                    Application.CutCopyMode = False
                    .Select
                End With
            End If
 
            'Show all data in the range
            My_Range.AutoFilter Field:=FieldNum
 
        Next cell
 
        'Delete the ws2 sheet
        On Error Resume Next
        Application.DisplayAlerts = False
        .delete
        Application.DisplayAlerts = True
        On Error GoTo 0
 
    End With
 
    'Turn off AutoFilter
    My_Range.Parent.AutoFilterMode = False
 
    If ErrNum > 0 Then
        MsgBox "Rename every WorkSheet name that start with ""Error_"" manually" _
             & vbNewLine & "There are characters in the name that are not allowed" _
             & vbNewLine & "in a sheet name or the worksheet already exist."
    End If
 
 
    Application.DisplayAlerts = False
   
    Dim sh As Worksheet
    For Each sh In Sheets
       If sh.UsedRange.Rows.Count = 1 Then sh.delete
    Next
    Application.DisplayAlerts = True
 
    'Restore ScreenUpdating, Calculation, EnableEvents, ....
    My_Range.Parent.Select
    ActiveWindow.View = ViewMode
    With Application
        .ScreenUpdating = True
        .EnableEvents = True
        .Calculation = CalcMode
    End With
 
 
End Sub
 
________________________________________________________________________________ 
 
 
Function LastRow(sh As Worksheet)
    On Error Resume Next
    LastRow = sh.Cells.Find(What:="*", _
                            After:=sh.Range("A1"), _
                            Lookat:=xlPart, _
                            LookIn:=xlValues, _
                            SearchOrder:=xlByRows, _
                            SearchDirection:=xlPrevious, _
                            MatchCase:=False).Row
    On Error GoTo 0
End Function
 
 
________________________________________________________________________________ 
 
Sub Mail_Worksheets_TEST()
'
' Mail_Worksheets_TEST Macro'
    Dim sh As Worksheet
    Dim wb As Workbook
    Dim FileExtStr As String
    Dim FileFormatNum As Long
    Dim TempFilePath As String
    Dim TempFileName As String
    Dim OutApp As Object
    Dim OutMail As Object
 
 
    TempFilePath = Environ$("temp") & "\"
 
 
    If Val(Application.Version) < 12 Then
        'You use Excel 97-2003
        FileExtStr = ".xls": FileFormatNum = -4143
    Else
        'You use Excel 2007-2016
        FileExtStr = ".xlsm": FileFormatNum = 52
    End If
 
 
    With Application
        .ScreenUpdating = False
        .EnableEvents = False
    End With
 
 
    Set OutApp = CreateObject("Outlook.Application")
 
 
    For Each sh In ThisWorkbook.Worksheets
        If sh.Range("L2").Value Like "?*@?*.?*" Then
 
 
            sh.Copy
            Set wb = ActiveWorkbook
 
 
            TempFileName = "Sheet " & sh.Name & " of " _
                         & ThisWorkbook.Name & " " & Format(Now, "dd-mmm-yy h-mm-ss")
 
 
            Set OutMail = OutApp.CreateItem(0)
 
 
            With wb
                .SaveAs TempFilePath & TempFileName & FileExtStr, FileFormat:=FileFormatNum
 
 
                On Error Resume Next
                With OutMail
                    .to = sh.Range("B2").Value
                    .CC = ""
                    .BCC = ""
                    .Subject = "OFFS!"
                    .Body = "Cymru Will Thrash England in the 6Nations!!"
                    .Send   'or use .Display
                End With
                On Error GoTo 0
 
 
                .Close Savechanges:=False
            End With
           
            Set OutMail = Nothing
 
 
            Kill TempFilePath & TempFileName & FileExtStr
 
 
        End If
    Next sh
 
 
    Set OutApp = Nothing
 
 
    With Application
        .ScreenUpdating = True
        .EnableEvents = True
    End With
End Sub

1st section splits 'Master' sheet into separate worksheets dependent on a unique identifier

Cheers
Small Paul.
 
Upvote 0

Forum statistics

Threads
1,220,965
Messages
6,157,119
Members
451,398
Latest member
rjsteward

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top