VBA code to create a new workbook from multiple sheets of current workbook

zmasterdevil

New Member
Joined
Dec 5, 2022
Messages
11
Office Version
  1. 365
Platform
  1. Windows
Hi Everybody,

I use a macro to do the following: It copies the current, active worksheet into a new workbook, names it, then prepares an email with the newly made workbook as the attachment. The new workbook is just temporary and for the email only. This macro is cobbled together from other people's code, as my coding skills are bad to non-existent. It works for single worksheet accounts, but some of my accounts have multiple sheets. I need to edit it so that it can copy multiple worksheets from the current workbook to make a new workbook. The tabs (or worksheets) that will be copied into the new workbook will be the same every time, so naming the tabs in the code will work fine.

I know this code probably already exists somewhere, but I've been searching for quite a while, and haven't found anything that I could get to work. I've pasted the code I'm using for creating and emailing single sheet workbooks below. Can anyone help me edit it to work for multiple sheets from the same original workbook? I appreciate any help that can be given.


Sub EmailActiveSheet_Distribution_1_540()

Dim OutApp As Object
Dim OutMail As Object
Dim TempFilePath As String
Dim FileExt As String
Dim TempFileName As String
Dim FileFullPath As String
Dim FileFormat As Variant
Dim Wb1 As Workbook
Dim Wb2 As Workbook
Dim strbody As String
Dim mySubject1 As Variant
Dim myBody1 As Variant

mySubject1 = Worksheets("540 Control Sheet").Range("D28").Value
myBody1 = Worksheets("540 Control Sheet").Range("D29").Value

With Application
.ScreenUpdating = False
.EnableEvents = False
End With
Set Wb1 = ThisWorkbook
ActiveSheet.Copy
Set Wb2 = ActiveWorkbook

'Below code will get the File Extension and
'the file format which we want to save the copy
'of the workbook with the active sheet.

With Wb2
If Val(Application.Version) < 12 Then
FileExt = ".xls": FileFormat = -4143
Else
Select Case Wb1.FileFormat
Case 51: FileExt = ".xlsx": FileFormat = 51
Case 52:
If .HasVBProject Then
FileExt = ".xlsm": FileFormat = 52
Else
FileExt = ".xlsx": FileFormat = 51
End If
Case 56: FileExt = ".xls": FileFormat = 56
Case Else: FileExt = ".xlsb": FileFormat = 50
End Select
End If
End With

'Save your workbook in your temp folder of your system
'below code gets the full path of the temporary folder
'in your system

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

'Now append a date and time stamp
'in your new file

TempFileName = Range("Z2").Value & " " & Format(Now + 31, "mmmm yyyy")

'Complete path of the file where it is saved
FileFullPath = TempFilePath & TempFileName & FileExt

'Now save your currect workbook at the above path
Wb2.SaveAs FileFullPath, FileFormat:=FileFormat

'Now open a new mail

Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)

strbody = "<Body style = font-size:12pt;font-family:Ariel>" & "Hi " & _
Range("z1").Value & ",<br><br>" & myBody1 & "<br><br>"

On Error Resume Next

With OutMail
.To = Range("Z3")
For Each cel In Range("z4:af4")
Dim sCC As String
sCC = sCC & ";" & cel.Value2
Next
.CC = Mid(sCC, 2) 'to cut off initial ";"
.Subject = Range("Z2") & " " & mySubject1
.htmlBody = strbody & _
"<img src='MY EMAIL SIGNATURE FILE'>" & .htmlBody
.Display

.Attachments.Add FileFullPath '--- full path of the temp file where it is saved
.Display 'use .Display or .Send depending on need
End With
On Error GoTo 0

'Since mail has been sent with the attachment
'Now close and delete the temp file from the
'temp folder
Wb2.Close SaveChanges:=False
Kill FileFullPath

'set nothing to the objects created
Set OutMail = Nothing
Set OutApp = Nothing

'Now set the application properties back to true
With Application
.ScreenUpdating = True
.EnableEvents = True
End With
End Sub
Function GetBoiler(ByVal sFile As String) As String
Dim fso As Object
Dim ts As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.readall
ts.Close
End Function
 

Excel Facts

Do you hate GETPIVOTDATA?
Prevent GETPIVOTDATA. Select inside a PivotTable. In the Analyze tab of the ribbon, open the dropown next to Options and turn it off
Please post code within code tags (vba icon on posting toolbar) to maintain indentation and readability. I usually won't bother to read code like that and I usually don't fix it. Today I'm feeling magnanimous, I guess ;)
I'll look at it after re-posting and in the meantime, perhaps this will help someone else to help you as well. I took some liberties in order to condense - hope you don't mind. I also corrected spelling of Arial.
VBA Code:
Sub EmailActiveSheet_Distribution_1_540()

Dim OutApp As Object, OutMail As Object
Dim TempFilePath As String, FileExt As String, TempFileName As String
Dim FileFullPath As String, strbody As String
Dim FileFormat As Variant, mySubject1 As Variant, myBody1 As Variant
Dim Wb1 As Workbook, Wb2 As Workbook

mySubject1 = Worksheets("540 Control Sheet").Range("D28").Value
myBody1 = Worksheets("540 Control Sheet").Range("D29").Value

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

Set Wb1 = ThisWorkbook
ActiveSheet.Copy
Set Wb2 = ActiveWorkbook

'Below code will get the File Extension and the file format which we want to save the copy
'of the workbook with the active sheet.

With Wb2
   If Val(Application.Version) < 12 Then
      FileExt = ".xls": FileFormat = -4143
   Else
      Select Case Wb1.FileFormat
         Case 51
            FileExt = ".xlsx": FileFormat = 51
         Case 52
            If .HasVBProject Then
               FileExt = ".xlsm": FileFormat = 52
            Else
               FileExt = ".xlsx": FileFormat = 51
            End If
         Case 56
            FileExt = ".xls": FileFormat = 56
         Case Else
            FileExt = ".xlsb": FileFormat = 50
      End Select
   End If
End With

'Save your workbook in your temp folder of your system
'below code gets the full path of the temporary folder in your system
TempFilePath = Environ$("temp") & "\"

'Now append a date and time stamp in your new file
TempFileName = Range("Z2").Value & " " & Format(Now + 31, "mmmm yyyy")

'Complete path of the file where it is saved
FileFullPath = TempFilePath & TempFileName & FileExt

'Now save your currect workbook at the above path
Wb2.SaveAs FileFullPath, FileFormat:=FileFormat

'Now open a new mail
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)

strbody = "<Body style = font-size:12pt;font-family:Arial>" & "Hi " & _
Range("z1").Value & ",<br><br>" & myBody1 & "<br><br>"

On Error Resume Next

With OutMail
   .To = Range("Z3")
   For Each cel In Range("z4:af4")
      Dim sCC As String
      sCC = sCC & ";" & cel.Value2
   Next
   .CC = Mid(sCC, 2) 'to cut off initial ";"
   .Subject = Range("Z2") & " " & mySubject1
   .htmlBody = strbody & "<img src='MY EMAIL SIGNATURE FILE'>" & .htmlBody
   '.Display '<<extra .Display not needed?
   .Attachments.Add FileFullPath '--- full path of the temp file where it is saved
   .Display 'use .Display or .Send depending on need
End With
On Error GoTo 0

'Since mail has been sent with attachment, close and delete the temp file from temp folder
Wb2.Close SaveChanges:=False
Kill FileFullPath

'set nothing to the objects created
Set OutMail = Nothing
Set OutApp = Nothing

'Now set the application properties back to true
With Application
   .ScreenUpdating = True
   .EnableEvents = True
End With

End Sub

Function GetBoiler(ByVal sFile As String) As String
Dim fso As Object, ts As Object

Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.readall
ts.Close

'I added next two lines also
Set fso = Nothing
Set ts = Nothing

End Function
 
Upvote 0
Micron,

Thank you for letting me know about the VBA code posting feature. I will make sure to use it going forward.
 
Upvote 0
If you are running this code from the same workbook you want to copy, then why not just copy the workbook as if doing a Save As? If you're copying from a different workbook and the source wb never contains code, then same thing but you'd save as .xlsx? Either way, I don't see why you'd have to worry about whether or not it had a vba project. And if you just want to copy the whole wb there's no need to worry about the sheets at all.
 
Upvote 0
If you are running this code from the same workbook you want to copy, then why not just copy the workbook as if doing a Save As? If you're copying from a different workbook and the source wb never contains code, then same thing but you'd save as .xlsx? Either way, I don't see why you'd have to worry about whether or not it had a vba project. And if you just want to copy the whole wb there's no need to worry about the sheets at all.
I don't think I'm understanding this comment correctly, but I'll explain what I'm doing, and maybe that will provide an answer.

I have workbooks with anywhere from 10 to 50 tabs (worksheets). Every month I have to send the worksheets for each account to the contact for that account. Most accounts just have one sheet (so my current code takes care of those). But about 50 accounts have more than one worksheet. For these accounts, I select all the sheets associated with the account (these are often not near each other in the workbook), click "Move or Copy" to a new workbook, then click "File", "Share" to send it as an attachment in an email, fill in all the email information, and send it. I would just like to automate these emails in the same way I have the single worksheet accounts automated.

I can't copy the whole workbook to send it because I can't send the account information of the wrong account to the wrong contact. The specific sheets that pertain to each account, are the only things I can send to each account contact. For example, I've uploaded a screen cap of the tabs of one of these workbooks. I would send all the green tabbed sheets to one person, all the blue tabbed sheets to another, etc...

I am perfectly fine with making a different module for each account this would be used for, so I do not need code that works for multiple accounts. The accounts names/numbers do not change, and once I have the code to pull out and email an accounts' specified worksheets, I can tweak that code for each account I use it for.

I hope this explained what I'm looking for better. If not, let me know and I will try to explain things differently.
 

Attachments

  • account tabs.PNG
    account tabs.PNG
    11.4 KB · Views: 19
Upvote 0
So it's not a case of one wb contains only sheets for one account, it's that any given wb can contains sheets for several accounts, and you only want to send those sheets to the account recipient?

Then as I see it, your options are
- to hard code the sheet names, but you will have to add/edit code as sheets are added/deleted/renamed/etc.
- loop over the selected sheets (simpler and won't depend on how many you select)

To loop over selected sheets add
Dim sht As Worksheet

instead of
Set Wb1 = ThisWorkbook
ActiveSheet.Copy

have

Set Wb1 = ThisWorkbook
Wb1.Activate
then have
VBA Code:
If ActiveWindow.SelectedSheets.Count = 0 Then Exit Sub
For Each sht In ActiveWindow.SelectedSheets
    ' then sheet copy goes here
Next
then workbook create code and email code goes outside the loop. Can you work with that? I didn't incorporate for you because I'm not seeing the need for worrying about the file type and I don't know what to do with it.
 
Last edited:
Upvote 0
Hi Micron,

Thank you for taking the time to help me with this.

Yes, exactly. Every workbook has multiple accounts. For example workbook 540 contains 12 accounts. And 4 of those accounts have either 2 or 3 sheets.

I added your code in, but I think I may have added it in incorrectly. Now when I run it, the whole workbook is saved as the attachment. This happens whether I select multiple sheets simultaneously, or just have one sheet selected. I copied my code here so you can see how I added it in (I probably added it in the wrong spot or something stupid like that).

You mentioned one way to accomplish what I want, would be hard coding the sheet names. As the account numbers and amount of sheets never change once created, I would only need to adjust the code when I make a new account, and I'm fine with this. Once I can get it to automatically copy all of an accounts' sheets to a new workbook (temporarily, I don't want the new workbooks after I email them), I was planning on adding a separate module for each account that has multiple sheets.

Ideally, I just want to go to the 1st sheet of an account, and click a button to email all sheets for that account to the contact.

VBA Code:
Sub EmailActiveSheet_Distribution_1_540()

Dim OutApp As Object, OutMail As Object
Dim TempFilePath As String, FileExt As String, TempFileName As String
Dim FileFullPath As String, strbody As String
Dim FileFormat As Variant, mySubject1 As Variant, myBody1 As Variant
Dim Wb1 As Workbook, Wb2 As Workbook
Dim sht As Worksheet

mySubject1 = Worksheets("540 Control Sheet").Range("D28").Value
myBody1 = Worksheets("540 Control Sheet").Range("D29").Value

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

Set Wb1 = ThisWorkbook
Wb1.Activate
Set Wb2 = ActiveWorkbook

If ActiveWindow.SelectedSheets.Count = 0 Then Exit Sub
For Each sht In ActiveWindow.SelectedSheets
' then sheet copy goes here
Next

'Below code will get the File Extension and the file format which we want to save the copy
'of the workbook with the active sheet.

With Wb2
   If Val(Application.Version) < 12 Then
      FileExt = ".xls": FileFormat = -4143
   Else
      Select Case Wb1.FileFormat
         Case 51
            FileExt = ".xlsx": FileFormat = 51
         Case 52
            If .HasVBProject Then
               FileExt = ".xlsm": FileFormat = 52
            Else
               FileExt = ".xlsx": FileFormat = 51
            End If
         Case 56
            FileExt = ".xls": FileFormat = 56
         Case Else
            FileExt = ".xlsb": FileFormat = 50
      End Select
   End If
End With

'Save your workbook in your temp folder of your system
'below code gets the full path of the temporary folder in your system
TempFilePath = Environ$("temp") & "\"

'Now append a date and time stamp in your new file
TempFileName = Range("Z2").Value & " " & Format(Now + 31, "mmmm yyyy")

'Complete path of the file where it is saved
FileFullPath = TempFilePath & TempFileName & FileExt

'Now save your currect workbook at the above path
Wb2.SaveAs FileFullPath, FileFormat:=FileFormat

'Now open a new mail
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)

strbody = "<Body style = font-size:12pt;font-family:Arial>" & "Hi " & _
Range("z1").Value & ",<br><br>" & myBody1 & "<br><br>"

On Error Resume Next

With OutMail
   .To = Range("Z3")
   For Each cel In Range("z4:af4")
      Dim sCC As String
      sCC = sCC & ";" & cel.Value2
   Next
   .CC = Mid(sCC, 2) 'to cut off initial ";"
   .Subject = Range("Z2") & " " & mySubject1
   .htmlBody = strbody & _
   "<img src='C:\Users\My Username\Signature_Image.png' width='95%'>" & .htmlBody
   '.Display '<<extra .Display not needed?
   .Attachments.Add FileFullPath '--- full path of the temp file where it is saved
   .Display 'use .Display or .Send depending on need
End With
On Error GoTo 0

'Since mail has been sent with attachment, close and delete the temp file from temp folder
Wb2.Close SaveChanges:=False
Kill FileFullPath

'set nothing to the objects created
Set OutMail = Nothing
Set OutApp = Nothing

'Now set the application properties back to true
With Application
   .ScreenUpdating = True
   .EnableEvents = True
End With

End Sub

Function GetBoiler(ByVal sFile As String) As String
Dim fso As Object, ts As Object

Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.readall
ts.Close

'Micron added next two lines
Set fso = Nothing
Set ts = Nothing

End Function
 
Upvote 0
' then sheet copy goes here
I meant the part of the code that does the copy goes there. That's somewhere from With Wb2 all the way to the Kill line. I think I would put the Outlook object creation and destruction (the Set lines) outside of the loop rather than inside, otherwise you'll create and destroy those objects for each sheet. If you want to post a link to a sample workbook I'll see what I can do but I've got a visitor right now. The sheets don't have to contain any info.

I still don't understand why you have to worry about the file type. If you post a link I'd want to know why it's necessary because it's quite possible that it's not.
 
Upvote 0
Hi Micron,

While looking around online, I finally found the piece of code I needed to make it work.

I just had to replace:
Set Wb1 = ThisWorkbook
ActiveSheet.Copy

with:
Set Wb1 = ThisWorkbook
Sheets(Array("540173", "540175", "540199")).Copy

and I just have to list the tab names inside the array like I did in the above code.

As for the file type, my initial code kept failing, and when searching online for a solution, I found that piece of code to add to it (someone had posted about the same problem I was having). I can see what it does, but I do not really understand why it's necessary. Like you said it probably isn't necessary, I'm sure there's a better way, but it made the code work, and that was my only goal.

But I want to thank you for trying to help me with this. It's much appreciated. Have a great day!
 
Upvote 0
Glad to see you got a solution that works for you. The downside is that if for some reason you decide that you need to re-send one sheet (e.g. because there was an edit to it) you cannot with that code. If you used code that sends selected sheets, then you can re-send that email with the one sheet. The downside to that is that you have to manually select the sheets you want each time - but how onerous is that? So there's a trade off, which is fine as long as you're aware of the shortcomings or benefits of each method.
 
Upvote 0

Forum statistics

Threads
1,223,886
Messages
6,175,190
Members
452,616
Latest member
intern444

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