Inserting text into incoming email Outlook 2013 locked read only - vba

I'm struggling to insert a string in an incoming email via VBA. The routine works fine when sending mail and it will work on incoming mail if the user clicks Actions Edit. The issue is that incoming mail is locked in read only mode. I've spent the past 13.5 hours searching everywhere. It is possible in earlier versions of Outlook, however Microsoft have removed the CommandBar functionality in Office 2013. Basically I need a way to allow the mail to be editable via a setting in VBA.
Here is the routine
Sub StampReference()
Dim objOL As Outlook.Application
Dim objNS As Outlook.NameSpace
Dim objDoc As Word.Document
Dim objSel As Word.Selection
strFullReference = "Reference: " & Reference
On Error Resume Next
Set objOL = Application
If objOL.ActiveInspector.EditorType = olEditorWord Then
Set objDoc = objOL.ActiveInspector.WordEditor
Set objNS = objOL.Session
Set objSel = objDoc.Windows(1).Selection
objSel.Move wdStory, -1
objDoc.Characters(1).InsertBefore _
strFullReference & vbCrLf & vbCrLf
objSel.Move wdParagraph, 1
End If
Set objOL = Nothing
Set objNS = Nothing
End Sub
EDIT
I've cracked it! Here is the way to change the mode for anyone interested. It is quick and dirty, however it shows how it can be done. I took some code that someone had written to do a Resend and played around with variants to stumble across the correct value to edit. I call this routine just before stamping the information in
Sub SetEditMode()
Dim myItem As Outlook.MailItem
Dim objInsp As Outlook.Inspector
Dim objActionsMenu As Office.CommandBarControl
Dim olNewMailItem As Outlook.MailItem
On Error Resume Next
Select Case TypeName(Application.ActiveWindow)
Case "Explorer"
Set myItem = ActiveExplorer.Selection.Item(1)
myItem.Display
Case "Inspector"
Set myItem = ActiveInspector.CurrentItem
Case Else
End Select
If myItem Is Nothing Then GoTo ExitProc
'edit mode
Set objInsp = ActiveInspector
objInsp.CommandBars.ExecuteMso ("EditMessage")
objActionsMenu.Execute
ExitProc:
End Sub

I've cracked it! Here is the way to change the mode for anyone interested. It is quick and dirty, however it shows how it can be done. I took some code that someone had written to do a Resend and played around with variants to stumble across the correct value to edit. I call this routine just before stamping the information in
Sub SetEditMode()
Dim myItem As Outlook.MailItem
Dim objInsp As Outlook.Inspector
Dim objActionsMenu As Office.CommandBarControl
Dim olNewMailItem As Outlook.MailItem
On Error Resume Next
Select Case TypeName(Application.ActiveWindow)
Case "Explorer"
Set myItem = ActiveExplorer.Selection.Item(1)
myItem.Display
Case "Inspector"
Set myItem = ActiveInspector.CurrentItem
Case Else
End Select
If myItem Is Nothing Then GoTo ExitProc
'edit mode
Set objInsp = ActiveInspector
objInsp.CommandBars.ExecuteMso ("EditMessage")
objActionsMenu.Execute
ExitProc:
End Sub
user2970334

Related

Outlook has exhausted all shared resources. Why?

With this bit of VBA code in MS Access I'm getting an error if its executed too often. The only way I've found to clear it is reboot my computer. Any idea why and what can I do?
Public Function HasOutlookAcct(strEmail As String) As Boolean
Dim OutMail As Object
Dim OutApp As OutLook.Application
Dim objNs As OutLook.NameSpace
Dim objAcc As Object
'https://stackoverflow.com/questions/67284852/outlook-vba-select-sender-account-when-new-email-is-created
Set OutApp = CreateObject("Outlook.Application")
Set objNs = OutApp.GetNamespace("MAPI")
For Each objAcc In objNs.Accounts
If objAcc.SmtpAddress = strEmail Then
HasOutlookAcct = True
Exit For
End If
Next
OutApp.Quit
Set objAcc = Nothing
Set objNs = Nothing
End Function
The code looks good. The NameSpace.Accounts property returns an Accounts collection object that represents all the Account objects in the current profile. I don't see any extensive or heavy usage of the Outlook object model, but creating a new Outlook Application instance in the method for checking whether a particular account is configured in Outlook or not is not the best way of using Outlook. Instead, I'd recommend running Outlook once at some point and getting all the configured emails for saving for future usage where necessary.
Also it makes sense to disable all COM add-ins to see whether it helps or not. The problem may be related to any specific COM add-in.
Appears the error is addressed by considering the user.
The assumption, based on my results, is Outlook is not cleaned up completely when the user's instance is closed with outApp.Quit.
When Outlook is open, outApp.Quit is not applied and Outlook remains open at the end.
When Outlook is not open, it is opened in the background and later closed with outApp.Quit.
There is zero or one instance of Outlook at any time.
Option Explicit
Public Function HasOutlookAcct(strEmail As String) As Boolean
'Reference Outlook nn.n Object Library
' Consistent early binding
Dim outApp As Outlook.Application
Dim objNs As Outlook.Namespace
Dim objAcc As Outlook.Account
Dim bCreated As Boolean
On Error Resume Next
Set outApp = GetObject(, "Outlook.Application")
On Error GoTo 0
If outApp Is Nothing Then
bCreated = True
Set outApp = CreateObject("Outlook.Application")
End If
Set objNs = outApp.GetNamespace("MAPI")
For Each objAcc In objNs.Accounts
'Debug.Print objAcc.SmtpAddress
If objAcc.SmtpAddress = strEmail Then
HasOutlookAcct = True
Exit For
End If
'Set objAcc = Nothing ' Additional cleanup if needed
Next
If bCreated = True Then ' Outlook object had to be created
outApp.Quit
End If
'Set outApp = Nothing ' Additional cleanup if needed
Set objNs = Nothing
End Function
Private Sub HasOutlookAcct_Test()
Dim x As Boolean
Dim sEmail As String
sEmail = "someone#somewhere.com"
Dim i As Long
For i = 1 To 50
Debug.Print i & ": " & sEmail
x = HasOutlookAcct(sEmail)
Debug.Print " HasOutlookAcct: " & x
DoEvents
Next
Debug.Print "done"
End Sub

How to send mail based on a draft then keep the draft?

We are updating mails from the drafts folder and sending them a few times a day.
I want to open a selected mail resend it save it so it goes back to drafts and then close it.
I tried below
Sub DRAFT()
Dim myItem As Outlook.MailItem
Dim objInsp As Outlook.Inspector
Dim objActionsMenu As Office.CommandBarControl
Dim olResendMsg As Outlook.MailItem
' get current item & open if needed
On Error Resume Next
Select Case TypeName(Application.ActiveWindow)
Case "Explorer"
Set myItem = Application.ActiveExplorer.Selection.Item(1)
myItem.Display
Case "Inspector"
Set myItem = Application.ActiveInspector.CurrentItem
Case Else
End Select
On Error GoTo 0
If myItem Is Nothing Then
MsgBox "Could not use current item. Please select or open a single email.", _
vbInformation
GoTo exitproc
End If
' run the resend command
Set objInsp = myItem.GetInspector
objInsp.CommandBars.ExecuteMso ("ResendThisMessage")
' save orig email
myItem.Save
' close orig email
myItem.Close
exitproc:
Set myItem = Nothing
Set objInsp = Nothing
Set objActionsMenu = Nothing
Set olResendMsg = Nothing
End Sub
You need to pass a OlInspectorClose enumeration value to the MailItem.Close method. It indicates the close behavior, i.e. the save mode. If the item displayed within the inspector has not been changed, this argument has no effect.
Name Value Description
olDiscard 1 Changes to the document are discarded.
olPromptForSave 2 User is prompted to save documents.
olSave 0 Documents are saved.
So, your code should like that:
' close orig email
myItem.Close olSave
Instead of executing the ribbon control programmatically using the CommandBars.ExecuteMso method you may try to create a cope of the source item and then send it.
The ExecuteMso method is useful in cases where there is no object model for a particular command. Works on controls that are built-in buttons, toggleButtons and splitButtons. On failure it returns E_InvalidArg for an invalid idMso, and E_Fail for controls that are not enabled or not visible.
Instead, you may use the MailItem.Copy method which creates another instance of an object.
Sub CopyItem()
Dim myNameSpace As Outlook.NameSpace
Dim myFolder As Outlook.Folder
Dim myNewFolder As Outlook.Folder
Dim myItem As Outlook.MailItem
Dim myCopiedItem As Outlook.MailItem
Set myNameSpace = Application.GetNamespace("MAPI")
Set myFolder = myNameSpace.GetDefaultFolder(olFolderInbox)
Set myNewFolder = myFolder.Folders.Add("Saved Mail", olFolderDrafts)
Set myItem = Application.CreateItem(olMailItem)
myItem.Subject = "Speeches"
Set myCopiedItem = myItem.Copy
myCopiedItem.To = "email#address.com"
myCopiedItem.Send()
End Sub
Although there is a mistake in myItem.Close, you cannot resend mail that has not been sent.
Option Explicit
Sub SendMailBasedOnPermanentDraft()
Dim myItem As MailItem
Dim objInsp As Inspector
Dim myCopyOfUnsentItemInDrafts As MailItem
' get current item & open if needed
On Error Resume Next
Select Case TypeName(ActiveWindow)
Case "Explorer"
Set myItem = ActiveExplorer.Selection.Item(1)
Case "Inspector"
Set myItem = ActiveInspector.CurrentItem
Case Else
End Select
On Error GoTo 0
If myItem Is Nothing Then
MsgBox "Could not use current item. Please select or open a single email.", vbInformation
GoTo exitProc
End If
If myItem.Sent = False Then
Set myCopyOfUnsentItemInDrafts = myItem.copy
With myCopyOfUnsentItemInDrafts
.Subject = "Copied " & Now & ": " & myItem.Subject
.Save
.Display ' change to .Send
End With
Else
MsgBox "Select or open a single unsent email.", vbInformation
End If
exitProc:
Set myItem = Nothing
Set objInsp = Nothing
Set myCopyOfUnsentItemInDrafts = Nothing
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.

Outlook VBA, display title in MsgBox

I have written the following module to display the Subject of an email that is currently open in Outlook, in a MsgBox.
Outlook 2010. Version 14.0.7140.5002.
I am getting a run-time error '424' Object Required.
With the debugger highlighting:
Set objItem = objApp.ActiveInspector.CurrentItem
Code is below:
Sub ShowTitle()
Dim objMail As Object
Set objItem = objApp.ActiveInspector.CurrentItem
Dim Title As String
Set objMail = objItem.Subject
Title = objItem
MsgBox (Title)
End Sub
Sub ShowTitle()
Dim objMail As Object
Set objItem = objApp.ActiveInspector.CurrentItem
Dim Title As String
Title = objItem.Subject
MsgBox (Title)
End Sub
Try this untested code.
Option Explicit
Sub ShowTitle()
'Dim objApp as Outlook.Application
Dim objItem As Object
Dim Title As String
' If exclusively in Outlook there is no need for objApp
'Set objApp = Outlook.Application
'Set objItem = objApp.ActiveInspector.CurrentItem
' or simpler
'Set objItem = Application.ActiveInspector.CurrentItem
' or simplest
Set objItem = ActiveInspector.CurrentItem
If objItem is mailitem then
Title = objItem.Subject
MsgBox (Title)
End if
'Set objApp = Nothing
Set objItem = Nothing
End Sub
Diane Poremsky over at Slipstick answered this one well in this article. Per her answer, make one module that contains this function:
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
Then, also per her answer, call that function with this line in your macro:
Set objItem = GetCurrentItem()
So, modifying your code, I made a second macro like this, which works for me:
Sub subjectLine()
Dim Title As String
Set objItem = GetCurrentItem()
Title = objItem.subject
MsgBox (Title)
End Sub
This way, you can run subjectLine() on either a selected email or an open email.

In Outlook, is it possible to run a macro on an email I select manually?

Is it possible to run a macro on an email that I manually select in my inbox. For instance, right click on the email and select "Send to >> Macro >> (show list of subroutines accepting Outlook.MailItem as a parameter)?
I think you will have to add a Button to the mail-ribbon. This Button can call an Routine.
In this Routine you use the active selection:
Sub example()
Dim myOlApp As Outlook.Application
Dim myNameSpace As Outlook.NameSpace
Set myOlApp = CreateObject("Outlook.Application")
Set myNameSpace = myOlApp.GetNamespace("MAPI")
Dim olExplorer As Explorer
Dim olfolder As MAPIFolder
Dim olSelection As Selection
Dim olitem As mailitem
Set olExplorer = Application.ActiveExplorer
Set olfolder = Application.ActiveExplorer.CurrentFolder
If olfolder.DefaultItemType = olMailItem Then
Set olSelection = olExplorer.Selection
end if
For Each olitem In olSelection
'do something
Next olitem
end sub
I hope you get this working...
Max
So, I was able to simplify Max's answer a bit, but he certainly pointed me in the right direction. Below is basically what I'm going with. After selecting an email in my inbox, I should be able to run this macro and proceed to work on it.
Sub example()
Dim x, mailItem As Outlook.mailItem
For Each x In Application.ActiveExplorer.Selection
If TypeName(x) = "MailItem" Then
Set mailItem = x
call fooMail(mailItem)
End If
Next
End Sub
Sub fooMail(ByRef mItem as Outlook.MailItem)
Debug.print mItem.Subject
End Sub