VBA - select the first file from a specific folder and reply all - excel

I saved multiple outlook msg on a specific folder named "email temp folder" and would to reply on the first msg in the folder.
However there is an error: type mismatch occur in the below lines.
Could you somebody help me on this please?
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 Outlook.MailItem
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 // error: type mismatch
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

It means that objFile is not of type Outlook.MailItem as you declared on top of your code.
Relying on the fact that your email template will always be the first item in the Files collection of the folder is not really stable, as the file might change position (probably is already not there, since you get the type mismatch error - you're probably trying to cast another type into a variable that is supposed to be a Outlook.MailItem type).
My suggestion is to reference directly to the file object; which means, in your code:
Set objFile = fso.GetFile("C:\...\mytemplate.msg")
and keep on running the code without the need to neither getFolder() nor looping For Each objFile in the Files collection, hoping that your file will be the first one.
However, best way to understand these kind of errors is to run the code in debug mode (press F8 and run line by line) and, by adding some watchers, figuring out what is what at run-time.

The Outlook object model doesn't provide any direct methods for opening .msg files on the disk. However, you can use the following workarounds to get the job done:
The CreateItemFromTemplate method of the Application class which allows to create a new Microsoft Outlook item from an Outlook template (.oft) or just a message file (.msg) and returns the new item. See How To: Create a new Outlook message based on a template for more information.
Use the ShellExecute method to open the file programmatically. Be aware, only one instance of the Outlook Application can be run at the same time. Thus, the message file will be opened in a new inspector window.
Sub CreateFromTemplate()
Dim MyItem As Outlook.MailItem
Set MyItem = Application.CreateItemFromTemplate("D:\message.msg")
MyItem.Display
End Sub

Related

Download either all the attachments or the latest in Outlook using VBA Excel [duplicate]

This question already has answers here:
Iterate all email items in a specific Outlook folder
(3 answers)
Closed last month.
I have been receiving an error:
Run-time error '-2147221233 (8004010f)';
The attempted operation failed. An Object could not be found.
In this line of code
Set objFolder = objNamespace.Folders("Inbox").Folders(strFolderName)
I am trying to download all the attached file from the folder to my specified path.
Here is my code:
Sub OLDownloader()
Dim objOutlook As Outlook.Application
Dim objNamespace As Outlook.Namespace
Dim objFolder As Outlook.Folder
Dim objItem As Object
Dim objAttachment As Outlook.Attachment
Dim strFolderName As String
Dim strSaveFolder As String
Dim Answer As String
Set objOutlook = Outlook.Application
Set objNamespace = objOutlook.GetNamespace("MAPI")
strFolderName = "Specials"
strSaveFolder = "C:\Users\Folder"
Set objFolder = objNamespace.Folders("Inbox").Folders(strFolderName)
Answer = MsgBox("Do you want to download the latest file?", vbYesNo, "Downloader")
If Answer = vbYes Then
Set objItem = objFolder.Items.GetLast
For Each objAttachment In objItem.Attachments
' Save the attachment to the specified folder
objAttachment.SaveAsFile strSaveFolder & objAttachment.Filename
Next objAttachment
Else
For Each objItem In objFolder.Items
For Each objAttachment In objItem.Attachments
' Save the attachment to the specified folder
objAttachment.SaveAsFile strSaveFolder & objAttachment.Filename
Next objAttachment
Next objItem
End If
End Sub
I have tried renaming the folder in my outlook, created new folder for this.
Changed strings into variables.
Instead of using the following line of code:
Set objFolder = objNamespace.Folders("Inbox").Folders(strFolderName)
To get any standard folder in Outlook like Inbox you need to use the GetDefaultFolder method of the Namespace class:
objNamespace.GetDefaultFolder(olFolderInbox).Folders(strFolderName)
Note, any subfolder may not exists, so I'd recommend iterating over all subfolders and checking the Name property to make sure it exists. If the folder doesn't exists you may consider creating it by using Folders.Add method.
Also I've noticed the following lines of code where you iterate over all items in the folder and try to save attached files if any:
For Each objItem In objFolder.Items
For Each objAttachment In objItem.Attachments
Instead, you need to use the Find/FindNext or Restrict methods of the Items class to get only items that have attached files, so you don't have to iterate over all items in the folder.
to get Inbox folder you should use:
Set objFolder = objOutlook.Session.GetDefaultFolder(olFolderInbox)

VBA Outlook Email Attachment Save Permissions

This script is suppose to loop through my outlook folder inbox-> Work Request
Then for each mail item in that folder download each attachment and save if to a file location.
Code seems to work fine in finding the folder and the correct emails however it is giving me an error message on the following line of code saying "Run-Time Error '-2147024891(80070005) Cannot save the attachment. You don't have the appropriate permissions to perform this operation."
I have tried multiple save location including our external cloud drive and my personal desktop. Currently the code is saving to my desktop and still says I do not have appropriate permissions to save. Any help would be greatly appreciated.
olAtt.SaveAsFile ("C:\Users\John Smith\Desktop\WOR Email Download")
The rest of the script is depicted below.
Option Explicit
Sub Download_Outlook_Attachemtns()
Dim olApp As Outlook.Application
Dim olNS As Outlook.Namespace
Dim olFolder As Outlook.MAPIFolder
Dim olItem As Object
Dim MailItem As Outlook.MailItem
Dim olAtt As Outlook.Attachment
Dim FileLocation As String
Set olApp = New Outlook.Application
Set olNS = olApp.GetNamespace("MAPI")
'single folder link to hidden sheet folders([admin].[Mailbox].text)
Set olFolder = olNS.Folders("JohnSmith#work.com")
Set olFolder = olFolder.Folders("Inbox")
Set olFolder = olFolder.Folders("Work Requests")
For Each olItem In olFolder.Items
If olItem.Class = olMail Then
Set MailItem = olItem
'Debug.Print MailItem.Subject
For Each olAtt In MailItem.Attachments
If MailItem.ReceivedTime > ThisWorkbook.Worksheets("Email_Info").Range("C6").Value Then
olAtt.SaveAsFile ("C:\Users\John Smith\Desktop\WOR Email Download")
'olAtt.SaveAs Filename:=Application.GetSaveAsFilename
End If
Next olAtt
End If
Next olItem
'Set olFolder = Nothing
'Set olNS = Nothing
End Sub
First of all, instead of iterating over all items in the folder:
For Each olItem In olFolder.Items
If olItem.Class = olMail Then
Set MailItem = olItem
You can find all items with attachments in the folder and iterate over them only. The Find/FindNext or Restrict methods of the Items class do the magic. Read more about these methods in the articles I wrote for the technical blog:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
For example, you can use the following search criteria (VBA syntax):
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:hasattachment" & Chr(34) & "=1"
Also it makes sense to optimize the code by changing the order of conditions:
For Each olAtt In MailItem.Attachments
If MailItem.ReceivedTime > ThisWorkbook.Worksheets("Email_Info").Range("C6").Value Then
Instead of checking the received time of the email for each attachment you can check it once for the email before iterating over attached files or, better yet, you may include another condition to the search criteria by using the logical AND operator in the search string.
Finally, you may try to check the Attachment.Type property value before trying to save anything to the disk. The property returns an OlAttachmentType constant indicating the type of the specified object.
You must include the file name besides the folder name. Currently, you are telling Outlook to save to a file conflicting with an existing folder name ("WOR Email Download"), hence the "no access" error - the file cannot be created since its name conflicts with an existing folder name. Change your code to
if olAtt.Type = olByValue Then
olAtt.SaveAsFile "C:\Users\John Smith\Desktop\WOR Email Download\" & olAtt.FileName
End If

Outlook array index out of bounds when trying to display MailItem after MailItem.Attachments.Add has failed

I'm calling Outlook from an Excel VBA macro to send an attachment via email. If for some reason an attachment cannot be added to the MailItem, I get the "Array index out of bounds" error when trying to display the MailItem.
When I checked value of MailItem.Attachments.Count, it showed 1, even though attachment was not added to the email. I tried removing the attachment using MailItem.Attachments.Remove 1, but count of attachments still shows 1 and the "Array index out of bounds" error still appears when trying to display.
I've come across this thread, which is about developing Office Add-Ins in C#, and it suggests releasing all COM objects. I'm not sure how to do it and if it's even relevant. I tried setting all objects except the MailItem to Nothing, but that didn't help.
UPD: The question that was suggested in comments does not solve my problem. In that question the wrong object was used to access the Attachments property. Here I'm using Outlook.MailItem.Attachments, which I believe is correct.
Here's the sample code:
Public Sub ForStackOverflow()
Dim OutlookApp As Object
Dim MailItem As Object
Dim Attachments As Object
Dim Attachment As Object
Set OutlookApp = CreateObject("Outlook.Application")
Set MailItem = OutlookApp.CreateItem(0)
With MailItem
.To = "test#test.com"
.Subject = "test"
.Body = "test"
Set Attachments = .Attachments
On Error Resume Next
Set Attachment = Attachments.Add("C:\Temp\ThisFileDoesNotExist.txt")
If Err.Number = 0 Then
On Error GoTo 0
.Send '<-- This works fine because attachment was added successfully
Else
On Error GoTo 0
'Attachment.Delete 'This and any of the below didn't work
'Set Attachment = Nothing
'Attachments.Remove 1
'Set Attachments = Nothing
.Display '<-- Error 440: Array index out of bounds on this line
End If
End With
End Sub
With On Error Resume Next you found there is something indicating there is an attachment, you cannot remove, that triggers an "Array index out of bounds" error.
Test for the file instead of applying the code of last resort, On Error Resume Next.
Option Explicit
Public Sub ForStackOverflow_FileExistsTest()
Dim OutlookApp As Object
Dim MailItem As Object
Dim pathFile As String
Set OutlookApp = CreateObject("Outlook.Application")
Set MailItem = OutlookApp.CreateItem(0)
With MailItem
pathFile = "C:\Temp\ThisFileDoesNotExist.txt"
If Len(dir(pathFile)) > 0 Then
.Attachments.Add (pathFile)
.Display
Else
MsgBox pathFile & " does not exist."
.Display
End If
End With
End Sub

Opening an Outlook .msg file with Excel VBA

I have the following code
Sub Kenneth_Li()
Dim objOL As Outlook.Application
Dim Msg As Outlook.MailItem
Set objOL = CreateObject("Outlook.Application")
inPath = "C:\Users\SiliconPlus\Desktop\Si+ Contact Lists\Contact_Si+"
thisFile = Dir(inPath & "\*.msg")
Do While thisFile <> ""
'Set Msg = objOL.CreateItemFromTemplate(thisFile)
'Or
Set Msg = objOL.OpenSharedItem(thisFile)
Msg.display
MsgBox Msg.Subject
thisFile = Dir
Loop
Set objOL = Nothing
Set Msg = Nothing
End Sub
When I use OpenSharedItem it gives a run-time error 438 Object doesn't support this property or method.
When I use CreateItemFromTemplate I get the following error:
Cannot open file: AUTO Andy Low Yong Cheng is out of the office (returning 22 09 2014).msg.
The file may not exist, you may not have permission to open it, or it may be open in another program.
Right-click the folder that contains the file, and then click properties to check your permissions for the folder.
I'm not 100% on what you're trying to get at with the code, but try this:
Sub LiminalMsgbx()
Dim outappp, outmaill As Object
Dim pthh As String
pthh = "C:\DeskTop\MyTemplate.oft"
Set outappp = CreateObject ("Outlook.Application")
Set outmaill = outapp.CreateItemFromTemplate(pthh)
With outmaill
.display
End With
Set outappp = Nothing
Set outmaill = Nothing
End Sub
You can also use .send instead of .display.
OpenSharedItem method is exposed by the Namespace object, not Application.
Set objOL = CreateObject("Outlook.Application")
set objNs = objOL.GetNamespace("MAPI")
objNs.Logon
...
Set Msg = objNs .OpenSharedItem(thisFile)
As for the second error, it is pretty unambiguous - the file cannot be found. You must provider a fully qualified file name with the folder path. You are only providing the file name.

VBA Runtime Error 13 Type Mismatch

I am trying to generate emails in a chosen Outlook folder from an Excel macro.
In the code below, 'TestDraft1' works, generating an email in the folder chosen by the user via the user the Namespace.PickFolder method.
However, since I want to generate many emails in the same folder, I need the user to be able to pick the folder just once. In 'TestDraft2' below, I try to save the folder as an Object, then pass it to the move function. This fails with "Runtime Error 13, Type Mismatch". The 'folder' variable gives the type "MAPIFolder".
What am I missing here? How is the object I assign to 'folder' different than the one I pass to 'Mailitem.move' ?
Edit Note that I'm using late-binding, which is why I'm defining my variables as Objects. I'd prefer to keep it that way, since I'd like to be able to distribute it without special configuration. What I really want to know is why the first version succeeds while the second version fails. Further details: My employer uses Office 2007.
Edit 2 The problem had nothing to do with what the type of object returned by PickFolder. It had to do with my misuse of VBA syntax. I've answered the question below, and I'm renaming the it to better address what I was really asking. Original title was: Returning an Outlook Folder object in Excel VBA using PickFolder
Sub test()
Call TestDraft1("test#example.com", "test1") ' succeeds
Call TestDraft2("test#example.com", "test2") ' fails
End Sub
Sub TestDraft1(recip As String, subj As String)
Dim OlApp As Object
Dim NS As Object
Dim OlMail As Object
Set OlApp = CreateObject("Outlook.Application")
Set NS = OlApp.GetNamespace("MAPI")
Set OlMail = OlApp.createitem(0) 'olMailitem = 0
OlMail.Subject = subj
OlMail.Recipients.Add (recip)
OlMail.Move (NS.PickFolder) ' pass the results of the folder-picker directly
End Sub
Sub TestDraft2(recip As String, subj As String)
Dim OlApp As Object
Dim NS As Object
Dim folder As Object
Dim OlMail As Object
Set OlApp = CreateObject("Outlook.Application")
Set NS = OlApp.GetNamespace("MAPI")
Set folder = NS.PickFolder ' save the results of the folder-picker...
' MsgBox (TypeName(folder)) ' returns "MAPIFolder
Set OlMail = OlApp.createitem(0) 'olMailitem = 0
OlMail.Subject = subj
OlMail.Recipients.Add (recip)
OlMail.Move (folder) ' ... and use the saved results of the folder-picker -> runtime error
End Sub
This shows how new I am to VBA syntax.
Replacing:
OlMail.Move (folder)
with
OlMail.Move folder
fixed the problem.
This is what I believe is going on: MailItem.Move returns no result, so it uses the non-parentheses syntax.
See: http://msdn.microsoft.com/en-us/library/office/gg278645
Thus, (folder) is interpreted as an expression, and returns the text value of the folder name inside the parentheses. Evidence:
Dim testobj as Object
Set testobj = (folder) ' fails: Object required
Dim testvar as Variant
testvar = (folder)
MsgBox (VarType(testvar) = vbString) ' returns True
So, while folder is an object of the correct type, (folder) is an expression which evaluates to a string.
maybe you just miss the objmail.save before moving it.
and your definitions are a problem for sure:
Change the first lines of your Sub as follows (untested):
Sub TestDraft2(recip As String, subj As String)
Dim olApp As Outlook.Application
Dim NS As Outlook.Namespace
Dim folder As Outlook.MAPIFolder
Dim OlMail As Outlook.mailitem
Set OlApp = CreateObject("Outlook.Application")
Set NS = OlApp.GetNamespace("MAPI")
Set folder = NS.PickFolder
that could help...

Resources