Search code examples
vbaemailoutlookevent-handlingoffice365

How to modify HTMLbody of email created from default ribbon button and keep default signature?


I want, when I create an email using the default ribbon button, to add a greeting to the body while also keeping the default signature.

I have a public function that uses TimeValue to calculate whether to add "Good morning," or "Good afternoon,". I call a sister function that adds it to the email.

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 built a class module for event handling to detect when a new inspector opens and that it is a mailitem. (Unfortunately, it's seems not able to detect yet whether it is a new email or if it is an email that's been retrieved and opened. 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 there because I also want to do this for inline replies. I have the event handlers for newExplorer and ActiveInlineResponse that I left out here because I'm focusing on 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 event handler for newInspector calls 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 exists, so the automatic signature doesn't fire.

Most of the solutions I see involve programmatically creating the email CreateItem(olMailItem), but I want to apply these to emails created by default.

Some other offered solutions I've seen might work, but I can't find examples I fully understand. Like inspector_activate from Event that fires after signature is added.

How do I get my automatic greeting and keep my automatic signature?


Solution

  • My own answer: I fixed it using the Inspector_Activate event as a SEPARATE sub. The default "new email" ribbon button creates a new inspector window that the _NewInspector event catches and sets as the active inspector. Inspector_Activate event then gets triggered as the email itself finishes its own creation/initialization process. Then the AddGreeting() function is called to edit the .HTMLbody and add the automated greeting.

    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/