Runtime Error '91 when saving email attachments - vba

We use a shared Outlook email box and we need to save some of the attachments from that email.
I need the macro to:
Allow user to select multiple emails and save all the attachments in the selection
Allow the user to select what folder to save the attachments in (it will be different every time)
Add the ReceivedTime to the file name as we get some email attachments with the same name but they are always received on different days
Not alter the original email (don't delete the attachment or add a note to the email)
I have combined different lines from macros I found.
On both lines with "***" I get
"Runtime error 91: "object variable or With block variable not set"
I remove the dateFormat and SaveAs and still get the runtime error on the SaveAs line.
Sub saveAttachment()
Dim objOL As Outlook.Application
Dim objMsg As Outlook.MailItem
Dim objAtt As Outlook.Attachment
Dim objSel As Outlook.Selection
Dim lngCount As Long
Dim sFolder As String
Dim dateFormat As String
dateFormat = Format(objMsg.ReceivedTime, "yyyy-mm-dd") '***
Dim xlObj As Excel.Application
Set xlObj = New Excel.Application
' Open the select folder prompt
With xlObj.FileDialog(msoFileDialogFolderPicker)
If .Show = -1 Then ' if OK is pressed
sFolder = .SelectedItems(1)
ElseIf .Show = 0 Then
MsgBox "Failed to select folder to save attachements to"
Exit Sub
End If
End With
xlObj.Quit
Set xlObj = Nothing
Set objOL = CreateObject("Outlook.Application")
Set objSelection = objOL.ActiveExplorer.Selection
For Each objMsg In objSelection
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
If lngCount > 0 Then
objAtt.SaveAsFile sFolder & "\" & objAtt.FileName & dateFormat '***
Else
MsgBox "No attachements selected"
End If
Next
End Sub
We are utilizing Office365.

First of all, you need to place the Format method inside the loop where the mail item is accessible and instantiated. Then you need to make sure the file path is valid and no forbidden symbols are used in the file name.
Set objOL = CreateObject("Outlook.Application")
Set objSelection = objOL.ActiveExplorer.Selection
For Each objMsg In objSelection
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
If lngCount > 0 Then
dateFormat = Format(objMsg.ReceivedTime, "yyyy-mm-dd")
objAtt.SaveAsFile sFolder & "\" & objAtt.FileName & dateFormat
Else
MsgBox "No attachements selected"
End If
Next
You may find the Getting started with VBA in Office article helpful.

Return an object property after you have the object.
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
' If desperate declare as Variant
Sub saveAttachment()
Dim objItem As Object
Dim objAtts As Attachments
Dim objAtt As Attachment
Dim objSel As Selection
Dim lngCount As Long
Dim sFolder As String
Dim dateFormat As String
Dim xlObj As Excel.Application
Set xlObj = New Excel.Application
' Open the select folder prompt
With xlObj.FileDialog(msoFileDialogFolderPicker)
If .Show = -1 Then ' if OK is pressed
sFolder = .SelectedItems(1)
ElseIf .Show = 0 Then
MsgBox "Failed to select folder to save attachements to"
Exit Sub
End If
End With
xlObj.Quit
Set xlObj = Nothing
' .Selection allows more than one item
Set objSel = ActiveExplorer.Selection
For Each objItem In objSel
' Mailitems only
If TypeOf objItem Is MailItem Then
dateFormat = Format(objItem.ReceivedTime, "yyyy-mm-dd")
Set objAtts = objItem.Attachments
lngCount = objAtts.Count
If lngCount > 0 Then
For Each objAtt In objAtts
Debug.Print sFolder & "\" & dateFormat & objAtt.FileName
objAtt.SaveAsFile sFolder & "\" & dateFormat & objAtt.FileName
Next
Else
MsgBox "No attachments in " & objItem.Subject
End If
End If
Next
End Sub

Related

Reply with .oft template and show images and attachments

When I create an email from an .oft template it doesn't show all the content of the e-mail.
It's missing content like images and/or attachments.
I tried to merge Sub reply1() and Sub reply2():
Sub Reply1()
Dim Original As Outlook.MailItem
Dim Reply As Outlook.MailItem
Set Original = Application.ActiveExplorer.Selection(1).Reply
Set Reply = Application.CreateItemFromTemplate("C:\Outlook\Mail.oft")
Original.HTMLBody = Reply.HTMLBody & Original.HTMLBody
Original.Display
End Sub
Sub Reply1()
This code doesn't show images or attachments of my own .oft mail.
It does show my e-mail signature but at the very bottom of both mails.
It does show the content of the e-mail I respond to correctly.
Sub Reply2()
Dim origEmail As MailItem
Dim replyEmail As MailItem
Set origEmail = ActiveExplorer.Selection(1)
Set replyEmail = CreateItemFromTemplate("C:\Outlook\Mail.oft")
replyEmail.To = origEmail.Reply.To
replyEmail.HTMLBody = replyEmail.HTMLBody & origEmail.Reply.HTMLBody
replyEmail.Recipients.ResolveAll
replyEmail.Display
Set origEmail = Nothing
Set replyEmail = Nothing
End Sub
Sub Reply2() does the opposite of Sub Reply1.
It shows the images and attachments of my own .oft mail.
It will not show my e-mail signature correctly.
It will not display the content of the mail I respond to correctly. The images are missing
Sub Reply1() Results:
Sub Reply2() Results
Embedded images are stored as hidden attachments on the email message. If you create a new Outlook item based on the template you need to re-attach the required images to get the message body rendered correctly. You can read more about that in the How to add an embedded image to an HTML message in Outlook 2010 thread.
Also, I have noticed the following code:
replyEmail.HTMLBody = replyEmail.HTMLBody & origEmail.Reply.HTMLBody
Remember, the HTML string should be a well-formed markup. If you want to insert something into the message body of an existing item you need to paste that inside the opening <body> and closing </body> elements. Otherwise, you may end up with a broken or improperly rendered message body. Even if Outlook do its great job by sorting most mistakes out.
The code below does work in my situation.
Sub Reply1()
Dim fromTemplate As MailItem
Dim reply As MailItem
Dim oItem As Object
Set fromTemplate = CreateItemFromTemplate("C:\Outlook\Mail.oft")
Set oItem = GetCurrentItem()
If Not oItem Is Nothing Then
Set reply = oItem.ReplyAll
CopyAttachments oItem, fromTemplate, reply
reply.HTMLBody = fromTemplate.HTMLBody & reply.HTMLBody
reply.Display
oItem.UnRead = False
End If
Set reply = Nothing
Set oItem = Nothing
End Sub
Function GetCurrentItem() As Object
Dim objApp As Outlook.Application
Set objApp = Application
On Error Resume Next
Select Case TypeName(objApp.ActiveWindow)
Case "Explorer"
Set GetCurrentItem = objApp.ActiveExplorer.Selection.Item(1)
Case "Inspector"
Set GetCurrentItem = objApp.ActiveInspector.CurrentItem
End Select
Set objApp = Nothing
End Function
Sub CopyAttachments(source1, source2, objTargetItem)
Set fso = CreateObject("Scripting.FileSystemObject")
Set fldTemp = fso.GetSpecialFolder(2) ' TemporaryFolder
strPath = fldTemp.Path & "\"
For Each objAtt In source1.Attachments
strFile = strPath & objAtt.fileName
objAtt.SaveAsFile strFile
objTargetItem.Attachments.Add strFile, , , objAtt.DisplayName
fso.DeleteFile strFile
Next
For Each objAtt In source2.Attachments
strFile = strPath & objAtt.fileName
objAtt.SaveAsFile strFile
objTargetItem.Attachments.Add strFile, , , objAtt.DisplayName
fso.DeleteFile strFile
Next
Set fldTemp = Nothing
Set fso = Nothing
End Sub
Forwarding an email retains attachments.
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
' If desperate declare as Variant
Sub Reply_Retain_Attachments()
Dim fromTemplate As MailItem
Dim origEmail As MailItem
Dim forwardEmail As MailItem
Set fromTemplate = CreateItemFromTemplate("C:\Outlook\Mail.oft")
Set origEmail = GetCurrentItem()
If Not origEmail Is Nothing Then
' Forward retains attachments
Set forwardEmail = origEmail.Forward
forwardEmail.HTMLBody = fromTemplate.HTMLBody & forwardEmail.HTMLBody
forwardEmail.To = origEmail.reply.To ' keep .reply here
forwardEmail.Recipients.ResolveAll
forwardEmail.Display
Else
' This may never occur
MsgBox "GetCurrentItem is nothing?"
End If
End Sub
Function GetCurrentItem() As Object
'On Error Resume Next ' uncomment if you find it necessary
Select Case TypeName(ActiveWindow)
Case "Explorer"
Set GetCurrentItem = ActiveExplorer.Selection.item(1)
Case "Inspector"
Set GetCurrentItem = ActiveInspector.CurrentItem
End Select
End Function

Save Attachment on arriving email

I created an Outlook rule to save an attachment then move it to the Deleted Items folder. The code works when I highlight the arrived email in the Inbox then move the email to the Deleted Items folder.
When the new email arrives, it is saving the attachment(s) from different email in the inbox and not moving the email to the Deleted Items folder.
The Outlook rule is:
Apply this rule after the message arrives
from Sender
and with Gift Card in the subject
and on this computer only
run Project1.SaveAttachments
Public Sub SaveAttachments(MItem As Outlook.Mailitem)
Dim objOL As Outlook.Application
Dim objMsg As Outlook.Mailitem 'Object
Dim objAttachments As Outlook.Attachments
Dim objSelection As Outlook.Selection
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strFolderpath As String
Dim objNamespace As Outlook.NameSpace
Dim objDestFolder As Outlook.MAPIFolder
On Error Resume Next
Set objOL = CreateObject("Outlook.Application")
Set objSelection = objOL.ActiveExplorer.Selection
strFolderpath = "Y:\"
For Each objMsg In objSelection
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
strDeletedFiles = ""
If lngCount > 0 Then
For i = lngCount To 1 Step -1
strFile = objAttachments.Item(i).FileName
strFile = strFolderpath & strFile
objAttachments.Item(i).SaveAsFile strFile
Next i
Set objNamespace = objOL.GetNamespace("MAPI")
Set objDestFolder = objNamespace.GetDefaultFolder(olFolderDeletedItems)
objMsg.Move objDestFolder
End If
Next
Set objAttachments = Nothing
Set objMsg = Nothing
Set objSelection = Nothing
Set objOL = Nothing
Set objNamespace = Nothing
Set objDestFolder = Nothing
End Sub
According to my test, you could save email attachment and delete it using the below code:
Sub SaveAutoAttach()
Dim object_attachment As Outlook.attachment
Dim saveFolder As String
Dim oOutlook As Object
Dim oOlns As Object
Dim oOlInb As Object
Dim unRead, m As Object, att As Object
Dim some As String, other As String
Const olFolderInbox = 6
'~~> Get Outlook instance
Set oOutlook = GetObject(, "Outlook.application")
Set oOlns = oOutlook.GetNamespace("MAPI")
Set oOlInb = oOlns.GetDefaultFolder(olFolderInbox)
'~~> Check if there are any actual unread emails
Set unRead = oOlInb.Items.Restrict("[UnRead] = True")
If unRead.Count = 0 Then
MsgBox "NO Unread Email In Inbox"
Else
some = ""
other = ""
saveFolder = "D:\"
For Each m In unRead
If m.Attachments.Count > 0 Then
For Each object_attachment In m.Attachments
' Criteria to save .doc files only
If InStr(object_attachment.DisplayName, ".doc") Then
object_attachment.SaveAsFile saveFolder & "\" & object_attachment.DisplayName
End If
Next
End If
m.Delete
Next m
End Sub
For more information, please refer to this link:
Auto Download Outlook Email Attachment – Code in VBA by Topbullets.com

Batch Print email attachments in order by date

Issue:
Hello, I have a macro, which saves me for a lot of clicking, but in the end not so much time, when it all comes down to it. The code allows me to mark everything within any mail folder. It will print the attachments within the email.
After this the error starts. Whenever I press this button, the items are ready and set to go, for a race to the printer. Meaning that whatever attachment that gets to the printer first, is the one that gets printed first. I then have to put everything in the right order when it has been printed.
My current code:
Sub BatchPrintAllAttachmentsinMultipleEmails()
Dim objFileSystem As Object
Dim strTempFolder As String
Dim objSelection As Outlook.Selection
Dim objItem As Object
Dim objMail As Outlook.MailItem
Dim objAttachments As Outlook.Attachments
Dim objAttachment As Outlook.Attachment
Dim objShell As Object
Dim objTempFolder As Object
Dim objTempFolderItem As Object
Dim strFilePath As String
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
strTempFolder = objFileSystem.GetSpecialFolder(2).Path & "\Temp for Attachments " & Format(Now, "YYYY-MM-DD_hh-mm-ss")
'Create a new temp folder
MkDir (strTempFolder)
Set objSelection = Outlook.Application.ActiveExplorer.Selection
For Each objItem In objSelection
If TypeOf objItem Is MailItem Then
Set objMail = objItem
Set objAttachments = objMail.Attachments
'Save all the attachments in the temp folder
For Each objAttachment In objAttachments
strFilePath = strTempFolder & "\" & objAttachment.FileName
objAttachment.SaveAsFile (strFilePath)
'Print all the files in the temp folder
Set objShell = CreateObject("Shell.Application")
Set objTempFolder = objShell.NameSpace(0)
Set objTempFolderItem = objTempFolder.ParseName(strFilePath)
objTempFolderItem.InvokeVerbEx ("print")
Next objAttachment
End If
Next
End Sub
Goal:
I would like the code to look for dates, and print the oldest first, and work its way up for the newest date. Is there by any chance, that I can put in a string, which gets the macro to "cool down" and send it to the printer in order, by the oldest date to the newest?

vba outlook - reply from a file from a folder

I dragged an outlook msg to a specific folder named "email temp folder" and would like to reply on that msg automatically.
The title name of the msg which I saved in "email temp folder" could be anything. It is not possible for me to get the file's title name. So I try to loop through the file in "email temp folder" and Set FileItemToUse = objFile
However, there is an error: object doesn't support this property or method on this line. .ReplyAll
How am I able to turn FileItemToUse into an outlook item?
Sub outlookActivate1()
Dim OutApp As Outlook.Application
Dim OutMail As Outlook.MailItem
Dim fso As New FileSystemObject
Dim objFolder As Object
Dim objFile As Object
Dim FileItemToUse As Object
Dim i As Long
Set OutApp = CreateObject("Outlook.Application")
strPath = "C:\Users\admin\Desktop\email temp folder" & "\"
strFiles = Dir(strPath & "*.*")
Set objFolder = fso.GetFolder(strPath)
For Each objFile In objFolder.Files
If i = 0 Then
Set FileItemToUse = objFile
End If
Next objFile
With FileItemToUse
.ReplyAll
.BCC = ""
.Subject = "Hi"
.HTMLBody = "testing"
.BodyFormat = olFormatHTML
.display
End With
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
Your code should look similar to the following:
Sub ReplyToFilesInFolder(SourceFolderName As String)
Dim FSO As Scripting.FileSystemObject
Dim SourceFolder As Scripting.Folder
Dim FileItem As Scripting.File
Dim strFile
Dim strFileType
Dim openMsg As MailItem
Dim strFolderpath As String
Set FSO = New Scripting.FileSystemObject
Set SourceFolder = FSO.GetFolder(SourceFolderName)
For Each FileItem In SourceFolder.Files
strFile = FileItem.name
' This code looks at the last 4 characters in a filename
' If we wanted more than .msg, we'd use Case Select statement
strFileType = LCase$(Right$(strFile, 4))
If strFileType = ".msg" Then
Debug.Print FileItem.Path
Set openMsg = Application.CreateItemFromTemplate(FileItem.Path)
' do whatever is needed to reply
openMsg.Close olDiscard
Set openMsg = Nothing
' end do whatever
End If
Next FileItem
Set FileItem = Nothing
Set SourceFolder = Nothing
Set FSO = Nothing
End Sub
This (untested) snipped was inspired by this article. Microsoft Scripting Runtime has to be included as project reference.
So I try to loop through the file in "email temp folder" and Set FileItemToUse = objFile
It is not possible to get the job done that way.
When you drag a message file (.msg) file to a specific folder the ItemAdd event is fired. So, you need to handle the event to get a MailItem object which corresponds a dropped file. Then you can use the Reply or ReplyAll methods.

VBA Outlook - Run automatically for all email in inbox?

I have the following code which I am using to save an email attachment into a folder. I want to make this vba run automatically each time I open outlook and check all emails in my creditchecks#hewden.co.uk inbox (non default inbox).
At the moment though it only checks the email which is selected in the active inbox. can someone please show me how I can edit my code to get it to do what I need. thanks
Public Sub SaveAttachments()
Dim objOL As Outlook.Application
Dim objMsg As Outlook.MailItem 'Object
Dim objAttachments As Outlook.Attachments
Dim objSelection As Outlook.Selection
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strFolderPath As String
Dim strDeletedFiles As String
Dim withParts As String
Dim withoutParts As String
' Get the path to your My Documents folder
On Error Resume Next
' Instantiate an Outlook Application object.
Set objOL = CreateObject("Outlook.Application")
' Get the collection of selected objects.
Set objSelection = objOL.ActiveExplorer.Selection
' The attachment folder needs to exist
' You can change this to another folder name of your choice
' Set the Attachment folder.
strFolderPath = "\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\ATTACHMENTS\"
' Check each selected item for attachments.
For Each objMsg In objSelection
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
If lngCount > 0 Then
' Use a count down loop for removing items
' from a collection. Otherwise, the loop counter gets
' confused and only every other item is removed.
For i = lngCount To 1 Step -1
' Get the file name.
strFile = objAttachments.item(i).FileName
If Right(strFile, 3) = "pdf" Then
' Combine with the path to the Temp folder.
withParts = strFile
withoutParts = Replace(withParts, ".pdf", "")
strFile = strFolderPath & withoutParts & "\" & strFile
' Save the attachment as a file.
objAttachments.item(i).SaveAsFile strFile
End If
Next i
End If
Next
ExitSub:
Set objAttachments = Nothing
Set objMsg = Nothing
Set objSelection = Nothing
Set objOL = Nothing
End Sub
Just need to edit some lines. Use something like objOL.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Parent.Folders("credutchecks#hewden.co.uk") to a folder in the same level of your Inbox folder. Here is your code modified:
Public Sub SaveAttachments()
Dim objOL As Outlook.Application
Dim objMsg As Outlook.MailItem 'Object
Dim objAttachments As Outlook.Attachments
Dim objSelection As Outlook.Selection
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strFolderPath As String
Dim strDeletedFiles As String
Dim withParts As String
Dim withoutParts As String
' Get the path to your My Documents folder
On Error Resume Next
' Instantiate an Outlook Application object.
Set objOL = CreateObject("Outlook.Application")
' Get the collection of selected objects.
'Set objSelection = objOL.ActiveExplorer.Selection
'Istead set this to the selected objects you just need to set to your email folder
'This is for a inbox same level folder
Set objSelection = objOL.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Parent.Folders("credutchecks#hewden.co.uk")
'This is for a folder inside the inbox folder
'Set objSelection = objOL.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("credutchecks#hewden.co.uk")
' The attachment folder needs to exist
' You can change this to another folder name of your choice
' Set the Attachment folder.
strFolderPath = "\\UKSH000-FILE06\Purchasing\New_Supplier_Set_Ups_&_Audits\ATTACHMENTS\"
' Check each selected item for attachments.
For Each objMsg In objSelection
Set objAttachments = objMsg.Attachments
lngCount = objAttachments.Count
If lngCount > 0 Then
' Use a count down loop for removing items
' from a collection. Otherwise, the loop counter gets
' confused and only every other item is removed.
For i = lngCount To 1 Step -1
' Get the file name.
strFile = objAttachments.item(i).FileName
If Right(strFile, 3) = "pdf" Then
' Combine with the path to the Temp folder.
withParts = strFile
withoutParts = Replace(withParts, ".pdf", "")
strFile = strFolderPath & withoutParts & "\" & strFile
' Save the attachment as a file.
objAttachments.item(i).SaveAsFile strFile
End If
Next i
End If
Next
ExitSub:
Set objAttachments = Nothing
Set objMsg = Nothing
Set objSelection = Nothing
Set objOL = Nothing
End Sub
To run it automatically when the Outlook starts just put it on the 'ThisOutlookSession' in the objects folder and name it 'Sub Application_Startup()'. Don't forget to enable macros before.