I've searched for days, piecing together code from other posts around Stack Overflow and from the learn.microsoft.com documentation for a solution to this and I'm struggling... It doesn't help that I'm relatively new to Outlook VBA.
What I want to happen is that when I create a new email using the default ribbon button, automatically add a greeting to the body while also keeping the default signature that is added. (Also wanting this to work for inline replies, but I'm focusing on this first).
I already have a public function that uses TimeValue
to calculate whether to add "Good morning," or "Good afternoon,", it works and returns as a string. I call a sister function that takes that string and adds it to the email. This part works.
Both of these are in a module called "AutoGreeting"
Option Explicit
Public Function Greeting() As String
' Defines greeting by time of day '
' Used in with the AddGreeting() function and clsMailHandler '
' If before noon, greeting is Good Morning'
If Time >= TimeValue("8:00 AM") And Time <= TimeValue("11:59 AM") Then
Greeting = "Good morning,"
' If after noon and before work ends, greeting is Good Afternoon'
ElseIf Time >= TimeValue("12:00 PM") And Time <= TimeValue("5:10 PM") Then
Greeting = "Good afternoon,"
End If
End Function
' call this function to add the above calculated greeting to an email '
' i.e. Call AddGreeting(NewlyCreatedEmail)
Public Function AddGreeting(ByRef DraftEmail As mailItem)
' DraftEmail is used with reference to any MailItem object '
' like in clsMailHander > NewInspector > objCurrentItem / objMailNew '
With DraftEmail
' Temporarily editing the subject for testing/debugging to make sure this works
.Subject = "AddGreeting Function"
' This adds the greeting but isn't able to keep the OG body AKA the auto-signature
' Because newInspector fires before signature is added
.HTMLBody = Greeting() & DraftEmail.HTMLBody
End With
End Function
I'm also building a class module for event handling that is able to detect when a new inspector opens and that it's a mailitem. (Unfortunately, it's seems it's not able to detect yet whether it's a new email or if it's an email that's been retrieved and opened. like if you double-click an email from your inbox, it opens in an inspector window. I do this by accident sometimes).
Explorers and the objMailReply
variable are in there because I also want this to work this inline replies. I have the event handlers for newExplorer
and ActiveInlineResponse
that I left out here because I'm focusing on just new emails in the inspectors for now.
Class module is called "clsMailHandler"
' Class for event handling of created emails
' re-start Outlook after compiling and saving changes to re-initialize class
' or run Application_Quit and Application_Startup from ThisOutlookSession cls
Option Explicit
Public WithEvents olApp As Outlook.Application
Public WithEvents objInspectors As Outlook.Inspectors
Public WithEvents objActInspector As Outlook.Inspector
Public WithEvents objExplorers As Outlook.Explorers
Public WithEvents objActExplorer As Outlook.Explorer
Public WithEvents objCurrentItem As Outlook.mailItem
Public WithEvents objMailNew As Outlook.mailItem
Public WithEvents objMailReply As Outlook.mailItem
' Called under Application_Startup in ThisOutlookSession as Handler class is created
Public Sub Class_Initialize()
Set olApp = Outlook.Application
' so far, all that's needed here is to initialize the explorers and inspectors w/ the app itself
Set objInspectors = olApp.Inspectors
Set objExplorers = olApp.Explorers
Set objActExplorer = olApp.ActiveExplorer
End Sub
' Called in Application_Quit as handler class is cleared
Public Sub Class_Terminate()
'when the application is closed, the class is terminated
'un-set variables
Set olApp = Nothing
Set objInspectors = Nothing
Set objActInspector = Nothing
Set objExplorers = Nothing
Set objActExplorer = Nothing
Set objMailNew = Nothing
Set objMailReply = Nothing
Set objCurrentItem = Nothing
End Sub
' Event handler for a new inspector window opening (i.e. new email is created)
' ISSUE - or when a received email is opened in a new window (double-click)
Public Sub objInspectors_NewInspector(ByVal Inspector As Outlook.Inspector)
Dim insType As String
Set objActInspector = Inspector
' this is just to keep names of object variables short and easy to remember
Set objCurrentItem = objActInspector.CurrentItem
' grab & test type name of current inspector item
insType = TypeName(objCurrentItem)
If insType = "MailItem" Then
' if its a mailItem - set variable that's more specific
Set objMailNew = objCurrentItem
' MsgBox is for debugging to make sure this fires
MsgBox ("New email has been created")
' Function from other module that is called to add the greeting
' Again, this works to add the greeting, but it doesn't keep the auto-signature
Call AddGreeting(objMailNew)
End If
End Sub
' This also fires if a received email that was opened in a new window is closed.
Public Sub objActInspector_Close()
' if the inspector window (created email) is closed, clear the variables
Set objMailNew = Nothing
Set objCurrentItem = Nothing
MsgBox ("Inspector has closed")
End Sub
This is how the class is initialized from within ThisOutlookSession
Option Explicit
'Instantiate the class on global application level
Dim EventHandler As clsMailHandler
Sub Application_Startup()
'Set custom variable as new instance of class
'to initialize the class (run Class_Initialize() sub)
Set EventHandler = New clsMailHandler
End Sub
Sub Application_Quit()
'Set handler to nothing to clear instance of class
Set EventHandler = Nothing
End Sub
The trouble I'm running into, is that the event handler for newInspector
can call the function that adds the greeting (and edits the subject for testing/debugging purposes), but then my auto-signature doesn't get added. I think because the newInspector
event fires off before the email actually exists, so the automatic signature doesn't fire. It's also complicated by my signature needing specific formatting and to contain an image, so just adding it as plain text doesn't work.
Most of the solutions I see involve programmatically creating the email CreateItem(olMailItem)
, but I don't want to do it that way. I want to apply these to the way an email is created by default.
Some things I've seen sound like they might work for what I need but I don't know how to implement them as I can't find examples that I understand. Namely, inspector_activate
like from this post Event that fires after signature is added.
How do I get my automatic greeting and keep my automatic signature?
EDIT: I fixed it using the inspector_Activate event. as a SEPARATE sub, so I can edit the email (successfully), after it finishes existing from the NewInspector event.
Public Sub objInspectors_NewInspector(ByVal Inspector As Outlook.Inspector)
If TypeName(Inspector.CurrentItem) = "MailItem" Then
Set objActInspector = Inspector
End If
End Sub
Public Sub objActInspector_Activate()
MsgBox ("Inspector Activate")
Set objMailNew = objActInspector.CurrentItem
If Len(objMailNew.EntryID) = 0 Then
Call AddGreeting(objMailNew)
End If
Set objActInspector = Nothing
End Sub
Found it on this random website: https://www.vboffice.net/en/developers/newinspector-and-inspector-activate/
CodePudding user response:
If there will be user interaction then the simplest solution is .Display
prior to .htmlbody = Greeting() & DraftEmail.htmlbody
Option Explicit
Private Sub test()
Dim objMailNew As MailItem
' Generate objMailNew any way you want
Set objMailNew = CreateItem(olMailItem)
' in your code this is
'Set objMailNew = objCurrentItem
Call AddGreeting(objMailNew)
objMailNew.Display
End Sub
Public Function Greeting() As String
' Defines greeting by time of day '
' Used in with the AddGreeting() function and clsMailHandler '
' If before noon, greeting is Good Morning'
If Time >= TimeValue("8:00 AM") And Time <= TimeValue("11:59 AM") Then
Greeting = "Good morning,"
' If after noon and before work ends, greeting is Good Afternoon'
ElseIf Time >= TimeValue("12:00 PM") And Time <= TimeValue("5:10 PM") Then
Greeting = "Good afternoon,"
End If
End Function
' call this function to add the above calculated greeting to an email '
' i.e. Call AddGreeting(NewlyCreatedEmail)
Public Function AddGreeting(ByRef DraftEmail As MailItem)
' DraftEmail is used with reference to any MailItem object '
' like in clsMailHander > NewInspector > objCurrentItem / objMailNew '
With DraftEmail
' Temporarily editing the subject for testing/debugging to make sure this works
.subject = "AddGreeting Function"
' Where user interaction is needed .Display is sufficient
'.Display
' Where user interaction is not needed
' This simulates .Display, without flashing the mail
Dim myInspector As Inspector
Set myInspector = .GetInspector
.htmlbody = Greeting() & DraftEmail.htmlbody
End With
End Function
CodePudding user response:
First, new items don't have the EntryID
property set, it is empty until the item is saved to the store in Outlook. So, checking the property value can help with distinguishing new items and saved ones.
Second, you need to wait for the first Activate
event of the Inspector class if you want to get the signature added to the message body. Otherwise, the default signature will be overwritten with your message body modifications.
Third, to preserve the default signature in the message body you must insert your greetings right after the opening <body>
tag in the HTMLBody
property value.