VBA Outlook Run-time Error - Could not send the message - vba

The VBA code shown below is for replying to an email with a specific template. The user selects the email that they want to reply to through a file dialog box, the code should then open a new email replying to the selected email. I am receiving the following error:
Run-time error '-2147352567 (80020009)'
Could not send the message.
When I click the "Help" button it takes me here: https://msdn.microsoft.com/en-us/VBA/Outlook-VBA/articles/olkcategory-backcolor-property-outlook
I can't imagine that link has anything to do with the error though. I have a feeling I'm doing something wrong with adding the reply email. Any help would be appreciated.
Here is my code:
Public Sub btnOK_Click()
Dim myOlApp As Outlook.Application
Dim myItem As Outlook.MailItem
Dim body As String
Set myOlApp = CreateObject("Outlook.Application")
Select Case templateUserForm.templateListBox.Text
Case "CWO"
ReplyTo
Set myItem = myOlApp.CreateItemFromTemplate("C:\example\temp\tempEmail.msg")
myItem.Reply = myOlApp.CreateItemFromTemplate("L:\example\CWO.oft") <--- Error occurs on this line
body = myItem.body
Unload templateUserForm
Unload inputUserForm
myItem.Display
End Select
End Sub
Public Sub ReplyTo()
Dim fso As Object
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
xlApp.Visible = False
Dim fd As Office.FileDialog
Set fd = xlApp.Application.FileDialog(msoFileDialogFilePicker)
fd.AllowMultiSelect = False
Dim selectedItem As Variant
If fd.Show = -1 Then
For Each selectedItem In fd.SelectedItems
Set fso = VBA.CreateObject("Scripting.FileSystemObject")
Call fso.CopyFile(fd.SelectedItems.Item(1), "C:\example\temp\tempEmail.msg")
Next
End If
End Sub

Typically you would create a reply object like this:
Set myReply = myItem.Reply
To start with an oft:
Dim myReply as Outlook.MailItem
Set myReply = myOlApp.CreateItemFromTemplate("L:\example\CWO.oft")
myReply.Display
Now that there is no error you have myReply to manipulate.
It appears you want this.
Set myItem = myOlApp.CreateItemFromTemplate("C:\example\temp\tempEmail.msg")
myReply = myOlApp.CreateItemFromTemplate("L:\example\CWO.oft")
myReply.body = myItem.body
Unload templateUserForm
Unload inputUserForm
myReply.Display
To make the result look more like a reply:
myReply.body = myReply.body & vbcr & myItem.reply.body
Depending on your templates you may want HTMLbody rather than body.

Related

SendUsingAccount SendAs permissions but not finding in index

I need to be able to send an email from VBA from a different email address. I have permissions to send from that address and can select it manually from the Outlook Message window. However, there is no index to it when I run the following code. All that shows up is my email address.
Sub Which_Account_Number()
'Don't forget to set a reference to Outlook in the VBA editor
Dim OutApp As Object
Dim I As Long
Set OutApp = CreateObject("Outlook.Application")
For I = 1 To OutApp.Session.Accounts.Count
MsgBox OutApp.Session.Accounts.Item(I) & " : This is account number " & I
Next I
End Sub
Is there a way to use the actual email address in the call? This is my test code for what I am trying to accomplish:
Sub SendMessagesTest()
Dim objOutlook As Object ' Outlook.Application
Dim objOutlookMsg As Object ' Outlook.MailItem
Dim objOutlookRecip As Object ' Outlook.Recipient
' Create the Outlook session.
Set objOutlook = CreateObject("Outlook.Application")
objOutlook.Session.Logon
' Create the message.
Set objOutlookMsg = objOutlook.CreateItem(0) '0 = olMailItem
With objOutlookMsg
' Set the Subject & Body of the message.
.Subject = "Test Subject"
.Body = "Test Body"
'.BodyFormat = 3 '3 = olFormatRichText (Late Binding)
'Change Item(1)to another number to use another account
Set .SendUsingAccount = "TestUser#test.com" 'objOutlook.Session.Accounts.Item(2) ' (Late Binding)
.Display
End With
Set objOutlook = Nothing
Set objOutlookMsg = Nothing
Set objOutlookRecip = Nothing
Exit Sub
End Sub
When I run it I get the error "Object Required".
I cannot use this type of code because I do not have an index number to use for the email address:
Set .SendUsingAccount = objOutlook.Session.Accounts.Item(1)
Edit: This is the code that I use to add an appointment item to another user's calendars which have been shared with me. Note: I have Publishing Editor permissions on the mailbox I am trying to Send As.
Sub CreateCalendarApptx()
Dim objApp As Object
Dim objNS As Object
Dim objFolder As Object
Dim objRecip As Object
Dim objAppt As Object
Dim objMsg As Object
Const olMailItem = 0
Const olFolderCalendar = 9
Dim strName As String
Set objApp = CreateObject("Outlook.Application")
Set objNS = objApp.getNamespace("MAPI")
Set objMsg = objApp.CreateItem(olMailItem)
strName = "OtherUser#Test.com"
'Select Calendar on which to place the appointment
'The Calendar can either be set with the name of the calendar or the Folder ID
If Left(strName, 3) = "ID:" Then
'Strip out the ID: identifier and leave just the ID
strName = Mid(strName, 5, Len(strName))
Set objFolder = objNS.GetFolderFromID(strName)
Else
Set objRecip = objMsg.Recipients.Add(strName)
objRecip.Resolve
If objRecip.Resolved Then
Set objFolder = objNS.GetSharedDefaultFolder(objRecip, olFolderCalendar)
End If
End If
Set objAppt = objFolder.Items.Add
objAppt.Subject = "Test"
objAppt.Display
Set objApp = Nothing
Set objNS = Nothing
Set objFolder = Nothing
Set objMsg = Nothing
Set objRecip = Nothing
Set objAppt = Nothing
End Sub
Edit 2:
I added another comment earlier, but the board didn't seem to like it because I attached a picture. The upshot is that when I send an email from the Outlook interface with a different name in the From: field, it sends successfully. However, when I hover over it I see "From: OtherUser#test.com Send Using Account: Me#test.com" If that is the case, the SendUsingAccount in VBA would be my email address, and there should be another property that would be the From: field.
change your statement from:
Set .SendUsingAccount = objOutlook.Session.Accounts.Item(1)
to:
Set .SendUsingAccount = objOutlook.Session.Accounts.Item("Testuser#test.com")
I was able to get SendUsingAccount to work -- except that items sat in the other account's Outbox and never were sent.
I finally got it to work by creating a mail profile that had the account I wanted to send as from as the only account. Then I added my mail account but left the SendUsingAccount as the default account for the profile to use. That way it continued to work.
But that's a bit inconvenient, except in my case the computer running the software is not my primary computer, so having the default profile set to a mail account other than mine will be bearable.
Are you sending on behalf of a delegate Exchange mailbox? Set the MailItem.SentOnBehalfOfName property.
Re: Comment to other answer post. It is unusual to do this "I can set appointments on other people's calendars from VBA".
If you have such rights, to the inbox of the other mailbox, you may be able to do this.
Option Explicit
Sub SendMailFromNonDefaultAccount()
' The only way I know this works is to
' use the "Add Account" button to add a non-default account.
' Not "Account Settings" which adds a mailbox to the default Account.
Dim myRecipient As recipient
Dim nonDefaultInboxFolder As Folder
Dim addMail As MailItem
' This is where your unusual permission, without adding an account, might yet kick in
Set myRecipient = Session.CreateRecipient("non-default email address as a string inside quotes")
Set nonDefaultInboxFolder = Session.GetSharedDefaultFolder(myRecipient, olFolderInbox)
' Add, not create, in non-default folder
Set addMail = nonDefaultInboxFolder.Items.Add
' The non-default email address will be in the "From"
addMail.Display
End Sub
With the code for the shared calendar applied to the shared inbox.
Option Explicit
Sub CreateCalendarAppt_and_mail()
Dim objApp As Object
Dim objNS As Object
Dim objFolder As Object
Dim objRecip As Object
Dim objAppt As Object
Dim objMsg As Object
Dim objInboxShared As Object
Dim objMsgShared As Object
' If there is no reference to the Outlook Object Library
Const olFolderInbox = 6
Const olMailItem = 0
Const olFolderCalendar = 9
Dim strName As String
Set objApp = CreateObject("Outlook.Application")
Set objNS = objApp.GetNamespace("MAPI")
Set objMsg = objApp.CreateItem(olMailItem)
strName = "OtherUser#Test.com"
Debug.Print strName
Set objRecip = objMsg.Recipients.Add(strName)
objRecip.Resolve
If objRecip.Resolved Then
Set objFolder = objNS.GetSharedDefaultFolder(objRecip, olFolderCalendar)
Set objAppt = objFolder.Items.Add
objAppt.Subject = "Test"
objAppt.Display
' Follows the format of the calendar code
' Looks the same as my original code
Set objInboxShared = objNS.GetSharedDefaultFolder(objRecip, olFolderInbox)
' objInboxShared.Display
Set objMsgShared = objInboxShared.Items.Add
objMsgShared.Subject = "Test Message"
objMsgShared.Display
End If
Set objApp = Nothing
Set objNS = Nothing
Set objFolder = Nothing
Set objMsg = Nothing
Set objRecip = Nothing
Set objAppt = Nothing
Set objInboxShared = Nothing
Set objMsgShared = Nothing
End Sub
I had two machines that were experiencing this same problem.
With the first machine, the user was being prompted to select a profile on opening Outlook. By setting the Control Panel/Mail profile setting so that it "Always use this profile", the problem was fixed.
The second machone had two profiles. Even though the main one was selected to "always use this profile", it still had the same problem. By removing the second profile, the problem went away.

Open Outlook using VBA in MS Access

I am trying to open Outlook when a button is clicked in MS Access, I have the following code which I have gathered online and after tinkering with it it is still not working. Here is my code:
Private Sub Command56_Click()
Dim obj
On Error Resume Next
Set obj = GetObject(, "Outlook.Application")
On Error GoTo 0
If obj Is Nothing Then Set obj = CreateObject("Outlook.Application")
End Sub
Does anyone have any suggestions?
No need to call GetObject. If Outlook is loaded, it will create a reference to it and if not, it will be loaded. It will not create a new instance though.
Private Sub Command56_Click()
Dim obj As Object
Set obj = CreateObject("Outlook.Application")
obj.Visible = True
'do work
obj.Quit '<-- This will close Outlook
Set obj = Nothing
End Sub
I have been using this procedure:
Private Sub OpenOutlook(emailAddress As String)
Dim objOutlook As Outlook.Application
Dim objOutlookMsg As Outlook.MailItem
Dim objOutlookRecip As Outlook.Recipient
Dim objOutlookAttach As Outlook.Attachment
' Create the Outlook session.
Set objOutlook = CreateObject("Outlook.Application")
' Create the message.
Set objOutlookMsg = objOutlook.CreateItem(olMailItem)
With objOutlookMsg
' Set the Subject, Body, and Importance of the message.
.Subject = "ISF"
.Body = "This is the body of the message." & vbCrLf & vbCrLf
.Recipients.Add (emailAddress)
' Add attachments to the message.
Set objOutlookAttach = .Attachments.Add("\\sql\images\" & Forms![WebQADocumentReview].FileName)
.Display
End With
Set objOutlook = Nothing
End Sub
But you can’t use similar code with Outlook due to how Outlook opens which is quite different from other Office products. Sometimes it is important to know that Outlook is open, for example to be sure that your mails created with VBA code are sent and not waiting in your outbox.
The code below is created by MVP Ben Clothier and can either retrieve an open instance of Outlook or open Outlook if it is closed. This uses a ‘self-healing object’ approach for returning an instance of Outlook.
https://www.rondebruin.nl/win/s1/outlook/openclose.htm
Add this to the Declarations
Dim g_olApp As Object
Create the below Subroutine
Private Sub fireOutlook()
Dim olShellVal As Long
On Error GoTo FIREOUTLOOK_ERR
Set g_olApp = GetObject(, "Outlook.Application") ' If outlook is open will create obj
' If closed this will goto the error handler and then resume
If g_olApp Is Nothing Then ' This checks if object was created
olShellVal = Shell("OUTLOOK", vbNormalNoFocus) ' Opens Outlook
Set g_olApp = CreateObject("Outlook.Application") ' Creates the Object
End If
FIREOUTLOOK_EXIT:
Exit Sub
FIREOUTLOOK_ERR:
If g_olApp Is Nothing Then
Err.Clear
Resume Next
Else
MsgBox Err.Description, , "Error Number: " & Err.Number
End If
GoTo FIREOUTLOOK_EXIT
End Sub
Once this is complete the global object can be used in any code involving outlook just make sure to call the fireOutlook subroutine first.

Activating specific email in Outlook with VBA & deleting signature from the copied text

I'm looking to use the get function in vba in order to activate a specific email in Outlook and then copy the body into a new email and send. I can use the getlast function to get the latest email in the inbox, however I would like to refine the code some more by selecting the latest email from a specific email address.
Also, I'd love how to know how to delete the signature from the text pasted into the new email.
Sub Negotiations()
Dim objMsg As Outlook.MailItem
Dim objItem As Outlook.MailItem
Dim BodyText As Object
Dim myinspector As Outlook.Inspector
Dim myItem As Outlook.MailItem
Dim NewMail As MailItem, oInspector As Inspector
Set myItem = Application.Session.GetDefaultFolder(olFolderInbox).Items.GetLast
myItem.Display
'copy body of current item
Set activeMailMessage = ActiveInspector.CurrentItem
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
' Create the message.
Set objMsg = Application.CreateItem(olMailItem)
'paste body into new email
Set BodyText = objMsg.GetInspector.WordEditor.Range
BodyText.Paste
'set up and send notification email
With objMsg
.To = "#gmail.com"
.Subject = "Negotiations"
.HTMLBody = activeMailMessage.HTMLBody
.Display
End With
End Sub
any help would be appreciated, thank you guys!
Open the Inbox folder using Namespace.GetDefaultFolder(olFolderInbox), retrieve the Items collection from MAPIFolder.Items. Sort the items (Items.Sort) on the ReceivedTime property, retrieve the latest email using Items.Find on the SenderEmailAddress property.
Dependant on what your property of .SenderEmailAddress returns, you can adapt what the while statement evaluates for. This should work for you, by first looking at the last e-mail, and then checking each previous e-mail for the correct sender address.
Sub display_mail()
Dim outApp As Object, objOutlook As Object, objFolder As Object
Dim myItems As Object, myItem As Object
Dim strSenderName As String
Set outApp = CreateObject("Outlook.Application")
Set objOutlook = outApp.GetNamespace("MAPI")
Set objFolder = objOutlook.GetDefaultFolder(olFolderInbox)
Set myItems = objFolder.Items
strSenderName = UCase(InputBox("Enter the e-mail Alias."))
Set myItem = myItems.GetLast
While Right(myItem.SenderEmailAddress, Len(strSenderName)) <> strSenderName
Set myItem = myItems.GetPrevious
Wend
myItem.Display
End Sub
Application.Session.GetDefaultFolder(olFolderInbox).Items.GetLast
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
First of all, I'd recommend breaking the chain of calls. Declare each property or method call on a separate line of code, so you will be able to debug the code at any time and see what happens under the hood.
The GetLast method returns the last object in the collectio. But it doesn't mean that the item is recieved last. You need to sort the collection using the Sort method as Dmitry suggested passing the ReceivedTime property as a parameter to sort on. Only in that case you will get the last recieved item from the collection.
The Outlook object model doesn't provide any special method or property for identifying signatures. You need to parse the message body and find it programmatically.
Sub Nego()
Dim objMsg As Outlook.MailItem
Dim myItem As Outlook.MailItem
Dim BodyText As Object
Dim Inspector As Outlook.MailItem
Dim olNameSpace As Outlook.NameSpace
Dim olfolder As Outlook.MAPIFolder
Dim msgStr As String
Dim endStr As String
Dim endStrStart As Long
Dim endStrLen As Long
Dim myItems As Outlook.Items
'Access folder Nego
Const olFolderInbox = 6
Set objOutlook = CreateObject("Outlook.Application")
Set objNamespace = objOutlook.GetNamespace("MAPI")
Set objInbox = objNamespace.GetDefaultFolder(olFolderInbox)
strFolderName = objInbox.Parent
Set objMailbox = objNamespace.Folders(strFolderName)
Set objFolder = objMailbox.Folders("Nego")
'Mark as read
For Each objMessage In objFolder.Items
objMessage.UnRead = False
Next
'Sort
Set myItems = objFolder.Items
For Each myItem In myItems
myItems.Sort "Received", False
Next myItem
myItems.GetLast.Display
'copy body of current item
Set activeMailMessage = ActiveInspector.CurrentItem
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
' Create the message.
Set objMsg = Application.CreateItem(olMailItem)
'paste body into new email
Set BodyText = objMsg.GetInspector.WordEditor.Range
BodyText.Paste
'Search Body
Set activeMailMessage = ActiveInspector.CurrentItem
endStr = "first line of signature"
endStrLen = Len(endStr)
msgStr = activeMailMessage.HTMLBody
endStrStart = InStr(msgStr, endStr)
activeMailMessage.HTMLBody = Left(msgStr, endStrStart + endStrLen)
'set up and send email
With objMsg
.To = "#email"
.Subject = "Nego"
.HTMLBody = activeMailMessage.HTMLBody
.HTMLBody = Replace(.HTMLBody, "First line of signature", " ")
.Send
End With
End Sub

Delete automatic Signature from forwarded emails VBA macro

Newbie Outlook VBA. intermediate Excel VBA. Windows 7 Professional, Outlook 2010
I have a script running from a rule that autoforwards all incoming emails. I need it as a rule because otherwise it will not forward the mails in the queue when Outlook loads.
I would like to have the default signature deleted when the mails are forwarded. As the reply is "blank" it is unnecessary to have the sig appended. I have found some code that supposedly worked in Outlook 2007 from the MSDN site. It compiles no errors, executes no errors. I have referenced MS Word in VBA. But the forwarded emails all have the signature still attached.
I cannot just delete the signature because I need it to be there on replies. The switch for the signature is for both replies and forwarded mail.
Here is the code:
Option Explicit
Sub Incoming3(MyMail As MailItem)
Dim strID As String
Dim strSender As String
Dim StrSubject As String
Dim objItem As Outlook.MailItem
Dim myItem As Outlook.MailItem
strID = MyMail.entryID
Set objItem = Application.Session.GetItemFromID(strID)
strSender = objItem.SenderName
StrSubject = objItem.Subject
StrSubject = strSender + ": " + StrSubject
objItem.Subject = StrSubject
objItem.AutoForwarded = False
Set myItem = objItem.Forward
myItem.Recipients.Add "bcc.hwb#gmail.com"
myItem.DeleteAfterSubmit = True
Call DeleteSig(objItem)
myItem.Send
Set myItem = Nothing
Set objItem = Nothing
End Sub
Sub DeleteSig(msg As Outlook.MailItem)
Dim objDoc As Word.Document
Dim objBkm As Word.Bookmark
On Error Resume Next
Set objDoc = msg.GetInspector.WordEditor
Set objBkm = objDoc.Bookmarks("_MailAutoSig")
If Not objBkm Is Nothing Then
objBkm.Select
objDoc.Windows(1).Selection.Delete
End If
Set objDoc = Nothing
Set objBkm = Nothing
End Sub
Any help with Outlook or VBA code would be much appreciated.
Processing the wrong mail in DeleteSig.
myItem.DeleteAfterSubmit = True
Call DeleteSig(myItem)
myItem.Send
Edit 2015 02 26
Debugging VBA Code
Private Sub Incoming3_test()
' Open a mailitem then click F8 repeatedly from this code
Dim currItem As MailItem
Set currItem = ActiveInspector.currentItem
Incoming3 currItem
End Sub
Sub Incoming3(MyMail As MailItem)
Dim myItem As Outlook.MailItem
Set myItem = MyMail.Forward
myItem.Subject = MyMail.senderName & ": " & MyMail.Subject
myItem.Recipients.Add "bcc.hwb#gmail.com"
myItem.DeleteAfterSubmit = True
myItem.Display ' If you are using F8 you can
' view the action taken in DeleteSig.
' Delete the line later.
Call DeleteSig(myItem)
'myItem.Send
Set myItem = Nothing
End Sub
Sub DeleteSig(msg As Outlook.MailItem)
Dim objDoc As Word.Document
Dim objBkm As Word.Bookmark
On Error Resume Next '<--- Very bad without On Error GoTo 0
Set objDoc = msg.GetInspector.WordEditor
Set objBkm = objDoc.Bookmarks("_MailAutoSig")
On Error GoTo 0
If Not objBkm Is Nothing Then
objBkm.Select ' <--- This is where the action starts.
objDoc.Windows(1).Selection.Delete
End If
Set objDoc = Nothing
Set objBkm = Nothing
End Sub
Edit 2015 02 26 - End
When you assign a VBA macro sub to run by the rule you get an instance of the MailItem object. For example:
Sub Incoming3(MyMail As MailItem)
The MyMail object represents an incoming email message which you should use in the code. But I see that you get a new instance:
strID = MyMail.entryID
Set objItem = Application.Session.GetItemFromID(strID)
There is no need to do so. Use the MyMail object in the code.
Also I see the following code:
Set objBkm = objDoc.Bookmarks("_MailAutoSig")
Try to run the code under the debugger and see whether the bookmark can be found. If there is no such bookmark you need to search the body for the first entry From: in the text and delete all the content before that keyword.
Finally, you may find the Getting Started with VBA in Outlook 2010 article in MSDN helpful.

Sending Emails from Excel VBA - Names Not Recognized

I am using the below code to send an email from excel using outlook:
Private Sub SendEmail()
Set OutlookApp = CreateObject("Outlook.Application")
Set OlObjects = OutlookApp.GetNamespace("MAPI")
Set newmsg = OutlookApp.CreateItem(olMailItem)
newmsg.Recipients.Add ("name#domain.com; name2#domain.com; name3#domain.com")
newmsg.Subject = "Test Mail"
newmsg.Body = "This is a test email."
'newmsg.Display
newmsg.Send
End Sub
The code works just fine, however I get the below error from Outlook when trying to send the email:
ErrorScreen http://im58.gulfup.com/GRENlB.png
The strange thing is that if I leave the new message open for two or three minutes the names automatically get resolved:
Working http://im74.gulfup.com/qmOYGQ.png
However this doesn't suit me as I don't want the message to be displayed before it's sent. I am looking to have it send as soon as I run the code.
Any suggestions or workarounds will be appreciated.
As a side note: I have tried enabling the "Allow commas as email separators" option in outlook, and then using the commas instead of the semicolons, but I am still facing the same problem.
UPDATE:
Below is the working code, as per Dmitry Streblechenko's answer:
Private Sub SendEmail()
Dim OutApp As Object
Dim OutMail As Object
Dim strbody As String
Set OutApp = CreateObject("Outlook.Application")
Set OlObjects = OutApp.GetNamespace("MAPI")
Set OutMail = OutApp.CreateItem(olMailItem)
On Error Resume Next
With OutMail
.To = ("name#domain.com; name2#domain.com; name3#domain.com")
.Subject = "Test Mail"
.Body = "This is a test email."
'.Display
.Send
End With
End Sub
You cannot pass multiple names to Recipients.Add - you get a single recipient with the name of "name#domain.com; name2#domain.com; name3#domain.com". Either call Recipients.Add 3 times once for each recipient or set the To property - it will parse multiple names.
You should add a call to ResolveAll to explicitely resolve all recipients.
Otherwise, resolution is done automatically after a short waiting period.
Example:
Sub CheckRecipients()
Dim MyItem As Outlook.MailItem
Dim myRecipients As Outlook.Recipients
Dim myRecipient As Outlook.Recipient
Set myItem = Application.CreateItem(olMailItem)
Set myRecipients = myItem.Recipients
myRecipients.Add("Aaron Con")
myRecipients.Add("Nate Sun")
myRecipients.Add("Dan Wilson")
If Not myRecipients.ResolveAll Then
For Each myRecipient In myRecipients
If Not myRecipient.Resolved Then
MsgBox myRecipient.Name
End If
Next
End If
End Sub
Code copied from here.