52

I am writing a VBA script in Access that creates and auto-populates a few dozen emails. It's been smooth coding so far, but I'm new to Outlook. After creating the mailitem object, how do I add the default signature to the email?

  1. This would be the default signature that is automatically added when creating a new email.

  2. Ideally, I'd like to just use ObjMail.GetDefaultSignature, but I can't find anything like it.

  3. Currently, I'm using the function below (found elsewhere on the internet) and referencing the exact path & filename of the htm file. But this will be used by several people and they may have a different name for their default htm signature file. So this works, but it's not ideal:

    Function GetBoiler(ByVal sFile As String) As String
    'Dick Kusleika
    Dim fso As Object
    Dim ts As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
    GetBoiler = ts.readall
    ts.Close
    End Function
    

    (Called with getboiler(SigString = "C:\Users\" & Environ("username") & "\AppData\Roaming\Microsoft\Signatures\Mysig.txt"))

Edit

Thanks to JP (see comments), I realize that the default signature is showing up at first, but it disappears when I use HTMLBody to add a table to the email. So I guess my question is now: How do I display the default signature and still display an html table?

Sub X()
    Dim OlApp As Outlook.Application
    Dim ObjMail As Outlook.MailItem

    Set OlApp = Outlook.Application
    Set ObjMail = OlApp.CreateItem(olMailItem)

    ObjMail.BodyFormat = olFormatHTML
    ObjMail.Subject = "Subject goes here"
    ObjMail.Recipients.Add "Email goes here"

    ObjMail.HTMLBody = ObjMail.Body & "HTML Table goes here"
    ObjMail.Display

End Sub
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
PowerUser
  • 11,583
  • 20
  • 64
  • 98
  • 1
    Have you checked out the forum on www.outlookcode.com, it's great for everything outlook : ) – Matt Donnan Jan 25 '12 at 12:44
  • Thanks for the tip. That led me to http://www.xtremevbtalk.com/archive/index.php/t-103235.html where someone said it wasn't possible with automation. I'm sure there's a way though. I'm not the first person with this question. – PowerUser Jan 25 '12 at 20:14
  • Do you have a default signature for new messages? I do, so when I create a message programmatically it is automatically populated with the default signature. – JimmyPena Jan 25 '12 at 20:58
  • @JP, Yes I have a signature and it is set as the default signature for new messages in the Tools menu. Except it isn't populating the mail object when I create it by automation. If you can tell me how, I'm listening. – PowerUser Jan 25 '12 at 22:12
  • I tested this using `Outlook.CreateItem(olMailItem).Display` in the Immediate Window. With a default signature, the message appears with the signature already there. Can you try the same test? – JimmyPena Jan 25 '12 at 22:42
  • @JP, yes, that does work exactly as you suggested, thanks, except for one important detail I left originally left out. I also need to include an HTML table in the body and I'm doing that by adding the html code to HTMLBody. However, once I reference HTMLBody, the signature disappears. Suggestions? – PowerUser Jan 26 '12 at 15:40
  • Add the table and append the existing HTMLBody (which has your sig), i.e. `ObjMail.HTMLBody = "HTML Table goes here" & vbCrLf & ObjMail.HTMLBody` – JimmyPena Jan 26 '12 at 15:42
  • Still doesn't work. After some trial&error, it seems that any attempt to put data into either `Objmail.HTMLBody` or `Objmail.Body` wipes out the signature. – PowerUser Jan 26 '12 at 16:52

15 Answers15

59

The code below will create an outlook message & keep the auto signature

Dim OApp As Object, OMail As Object, signature As String

Set OApp = CreateObject("Outlook.Application")
Set OMail = OApp.CreateItem(0)

With OMail
    .Display
End With

signature = OMail.body

With OMail
    '.To = "someone@somedomain.com"
    '.Subject = "Type your email subject here"
    '.Attachments.Add
    .body = "Add body text here" & vbNewLine & signature
    '.Send
End With

Set OMail = Nothing
Set OApp = Nothing
Andre
  • 26,751
  • 7
  • 36
  • 80
Julia Jones
  • 606
  • 6
  • 2
  • 12
    This is pretty much what I went with. The only difference is that since my email body is html, I used `.HTMLbody`, not `.body`. Simple and direct. – PowerUser Mar 01 '13 at 19:10
  • 2
    Thanks, this worked for what I was interested in too! To any future users, make sure if you want the `.HTMLbody` to change it in both locations. – enderland May 16 '13 at 15:43
  • Thanks - I'm trying to count the number of default signature files.. so this works. .Display followed by .Count and .Close gets me what i want, but is there any way to Display hidden? – jcansell Jul 19 '13 at 14:04
  • This is working and I am able to add auto signature in email but somehow Signature gets added on the top of the email. can someone help me to identify how to add that in the end. – HBhatia May 28 '15 at 14:31
  • Note that you do not need to call MailItem.Display unless you actually want to display the message. You can simply access the MailItem.GetInspector property - see my answer below. – Dmitry Streblechenko Sep 04 '15 at 06:47
  • 5
    if you want to use .HTMLbody this is not a propper solution breause it creates invalid HTML. The signature (OMail.body) contains a string starting with so you cannot just prepend your text – Stefan Feb 14 '17 at 16:16
  • 2
    @Stefan - just tagging you for reference clarity; I imagine you personally know this: If you need to get rid of the tags on the signature so you can easily add it into a `.HTMLbody` simply replace the signature setting line with `signature = Mid(OMail.body,6,Len(OMail.Body)-13)`. – Isaac Reefman Jun 25 '18 at 01:44
  • Why not `With OMail .Display;signature =.body;.to=.. end with`, so everything in the with block. – Timo Oct 21 '21 at 14:57
19

My solution is to display an empty message first (with default signature!) and insert the intended strHTMLBody into the existing HTMLBody.

If, like PowerUser states, the signature is wiped out while editing HTMLBody you might consider storing the contents of ObjMail.HTMLBody into variable strTemp immediately after ObjMail.Display and add strTemp afterwards but that should not be necessary.

Sub X(strTo as string, strSubject as string, strHTMLBody as string)

   Dim OlApp As Outlook.Application   
   Dim ObjMail As Outlook.MailItem 

   Set OlApp = Outlook.Application
   Set ObjMail = OlApp.CreateItem(olMailItem)

   ObjMail.To = strTo
   ObjMail.Subject = strSubject   
   ObjMail.Display
   'You now have the default signature within ObjMail.HTMLBody.
   'Add this after adding strHTMLBody
   ObjMail.HTMLBody = strHTMLBody & ObjMail.HTMLBody

   'ObjMail.Send 'send immediately or 
   'ObjMail.close olSave 'save as draft
   'Set OlApp = Nothing

End sub
Mab879
  • 608
  • 16
  • 33
Rick van Dam
  • 191
  • 1
  • 4
  • 1
    You don't need to display the message - simply accessing MailItem.GetInspector on a new message will insert the signature. Once you have the signature, you should not concatenate 2 HTML strings - they must be merged: the simplest way is to insert your HTML after the first occurrence of ">" that follows " – Dmitry Streblechenko Feb 19 '13 at 23:39
  • @DmitryStreblechenko, I'm trying the `Objmail.GetInspecter.Activate` and it looks like it does the same thing as `Objmail.Display`, Either way, it displays the email (which is fine with me since there isn't alot to create) – PowerUser Mar 01 '13 at 19:01
  • I agree - I couldn'tfind a way to stop the email displaying – jcansell Jul 19 '13 at 14:05
  • 2
    I appreciate that this answer (unlike the accepted one) was courteous enough to add a sentence on the strategy the code uses, instead of just throwing a block of code at you with no explanation at all. Granted, this is a basic example. But a single sentence is all it took. And describing the strategy before delving into code is just good communication and good manners. – Syntax Junkie Aug 03 '16 at 22:10
  • @PowerUser, if you create an Inspector object `Dim ObjInspector As Outlook.Inspector`, you can access `MailItem.GetInspector` without activating it: `Set ObjInspector = ObjMail.GetInspector`. I think this is what @DmitryStreblechenko is recommending. This prevents the email from displaying. – Nathan Dudley Jul 23 '19 at 17:29
  • This MailItem.GetInspector seems to break my program on last Office updates (build 2104 13929.20296), anyone else experiencing this ? .Send method fails giving a "Sorry, something went wrong. You may want to try again" – Marçal Torroella May 06 '21 at 11:09
15
Dim OutApp As Object, OutMail As Object, LogFile As String
Dim cell As Range, S As String, WMBody As String, lFile As Long

S = Environ("appdata") & "\Microsoft\Signatures\"
If Dir(S, vbDirectory) <> vbNullString Then S = S & Dir$(S & "*.htm") Else S = ""
S = CreateObject("Scripting.FileSystemObject").GetFile(S).OpenAsTextStream(1,  -2).ReadAll

WMBody = "<br>Hi All,<br><br>" & _
         "Last line,<br><br>" & S 'Add the Signature to end of HTML Body

Just thought I'd share how I achieve this. Not too sure if it's correct in the defining variables sense but it's small and easy to read which is what I like.

I attach WMBody to .HTMLBody within the object Outlook.Application OLE.

Hope it helps someone.

Thanks, Wes.

Wesley
  • 151
  • 1
  • 2
5

I figured out a way, but it may be too sloppy for most. I've got a simple Db and I want it to be able to generate emails for me, so here's the down and dirty solution I used:

I found that the beginning of the body text is the only place I see the "<div class=WordSection1>" in the HTMLBody of a new email, so I just did a simple replace, replacing

"<div class=WordSection1><p class=MsoNormal><o:p>"

with

"<div class=WordSection1><p class=MsoNormal><o:p>" & sBody

where sBody is the body content I want inserted. Seems to work so far.

.HTMLBody = Replace(oEmail.HTMLBody, "<div class=WordSection1><p class=MsoNormal><o:p>", "<div class=WordSection1><p class=MsoNormal><o:p>" & sBody)
PowerUser
  • 11,583
  • 20
  • 64
  • 98
Eliot K
  • 614
  • 5
  • 16
  • This worked EXCELLENTLY for me! Far from quick and dirty, this was the most elegant answer of all. As noted earlier, just remember to call .display *before* you call the function shown above, otherwise there's no signature inserted yet. – David at HotspotOffice Jul 13 '17 at 05:35
5

I constructed this approach while looking for how to send a message on a recurring schedule. I found the approach where you reference the Inspector property of the created message did not add the signature I wanted (I have more than one account set up in Outlook, with separate signatures.)

The approach below is fairly flexible and still simple.

    Private Sub Add_Signature(ByVal addy as String, ByVal subj as String, ByVal body as String)
       Dim oMsg As MailItem
       Set oMsg = Application.CreateItem(olMailItem)
       oMsg.To = addy
       oMsg.Subject = subj
       oMsg.Body = body
       Dim sig As String
       ' Mysig is the name you gave your signature in the OL Options dialog 
       sig = ReadSignature("Mysig.htm")
       oMsg.HTMLBody = Item.Body & "<p><BR/><BR/></p>" & sig ' oMsg.HTMLBody
       oMsg.Send
       Set oMsg = Nothing
    End Sub

    Private Function ReadSignature(sigName As String) As String
       Dim oFSO, oTextStream, oSig As Object
       Dim appDataDir, sig, sigPath, fileName As String
       appDataDir = Environ("APPDATA") & "\Microsoft\Signatures"
       sigPath = appDataDir & "\" & sigName

       Set oFSO = CreateObject("Scripting.FileSystemObject")
       Set oTextStream = oFSO.OpenTextFile(sigPath)
       sig = oTextStream.ReadAll
       ' fix relative references to images, etc. in sig
       ' by making them absolute paths, OL will find the image
       fileName = Replace(sigName, ".htm", "") & "_files/"
       sig = Replace(sig, fileName, appDataDir & "\" & fileName)
       ReadSignature = sig
    End Function
Mozzis
  • 421
  • 4
  • 7
4

I need 50 rep to post a comment against the Signature Option I found most helpful, however I had an issue with images not showing correctly so I had to find a work around. This is my solution:

Using @Morris Maynard's answer as a base https://stackoverflow.com/a/18455148/2337102 I then had to go through the following:

Notes:
Back up your .htm file before starting, copy & paste to a secondary folder

  1. You will be working with both the SignatureName.htm and the SignatureName_files Folder

  2. You do not need HTML experience, the files will open in an editing program such as Notepad or Notepad++ or your specified HTML Program

  3. Navigate to your Signature File location (standard should be C:\Users\"username"\AppData\Roaming\Microsoft\Signatures)

  4. Open the SignatureName.htm file in a text/htm editor (right click on the file, "Edit with Program")

  5. Use Ctrl+F and enter .png; .jpg or if you don't know your image type, use image001 You will see something like: src="signaturename_files/image001.png"

  6. You need to change that to the whole address of the image location C:\Users\YourName\AppData\Roaming\Microsoft\Signatures\SignatureNameFolder_files\image001
    or
    src="E:\location\Signatures\SignatureNameFolder_files\image001.png"

  7. Save your file (overwrite it, you had of course backed up the original)

  8. Return to Outlook and Open New Mail Item, add your signature. I received a warning that the files had been changed, I clicked ok, I needed to do this twice, then once in the "Edit Signatures Menu".

    Some of the files in this webpage aren't in the expected location. Do you want to download them anyway? If you're sure the Web page is from a trusted source, click Yes."

  9. Run your Macro event, the images should now be showing.

Credit
MrExcel - VBA code signature code failure: http://bit.ly/1gap9jY

Community
  • 1
  • 1
MrsAdmin
  • 548
  • 5
  • 12
  • 34
  • 1
    So, your suggestion is how to add images to a signature. Interesting. When I posted the question originally, I was only thinking about text signatures. But this could be useful in other ways. Thanks. – PowerUser Feb 14 '14 at 22:30
  • @PowerUser thanks for commenting. Unless you know HTML code it's best if you insert the images whilst creating the signature in OL. Some of my sigs have them, some don't. My non-default sig does have the images which is why I was hunting for a solution. :) Your Question is the most used and directed to for people wanting to add signatures using VBA. I thought it may indeed be useful for some. :) I hope it helps others that come looking. Have a great day! – MrsAdmin Feb 16 '14 at 10:00
4

I have made this a Community Wiki answer because I could not have created it without PowerUser's research and the help in earlier comments.

I took PowerUser's Sub X and added

Debug.Print "n------"    'with different values for n
Debug.Print ObjMail.HTMLBody

after every statement. From this I discovered the signature is not within .HTMLBody until after ObjMail.Display and then only if I haven't added anything to the body.

I went back to PowerUser's earlier solution that used C:\Users\" & Environ("username") & "\AppData\Roaming\Microsoft\Signatures\Mysig.txt"). PowerUser was unhappy with this because he wanted his solution to work for others who would have different signatures.

My signature is in the same folder and I cannot find any option to change this folder. I have only one signature so by reading the only HTM file in this folder, I obtained my only/default signature.

I created an HTML table and inserted it into the signature immediately following the <body> element and set the html body to the result. I sent the email to myself and the result was perfectly acceptable providing you like my formatting which I included to check that I could.

My modified subroutine is:

Sub X()

  Dim OlApp As Outlook.Application
  Dim ObjMail As Outlook.MailItem

  Dim BodyHtml As String
  Dim DirSig As String
  Dim FileNameHTMSig As String
  Dim Pos1 As Long
  Dim Pos2 As Long
  Dim SigHtm As String

  DirSig = "C:\Users\" & Environ("username") & _
                               "\AppData\Roaming\Microsoft\Signatures"

  FileNameHTMSig = Dir$(DirSig & "\*.htm")

  ' Code to handle there being no htm signature or there being more than one

  SigHtm = GetBoiler(DirSig & "\" & FileNameHTMSig)
  Pos1 = InStr(1, LCase(SigHtm), "<body")

  ' Code to handle there being no body

  Pos2 = InStr(Pos1, LCase(SigHtm), ">")

  ' Code to handle there being no closing > for the body element

   BodyHtml = "<table border=0 width=""100%"" style=""Color: #0000FF""" & _
         " bgColor=#F0F0F0><tr><td align= ""center"">HTML table</td>" & _
         "</tr></table><br>"
  BodyHtml = Mid(SigHtm, 1, Pos2 + 1) & BodyHtml & Mid(SigHtm, Pos2 + 2)

  Set OlApp = Outlook.Application
  Set ObjMail = OlApp.CreateItem(olMailItem)
  ObjMail.BodyFormat = olFormatHTML
  ObjMail.Subject = "Subject goes here"
  ObjMail.Recipients.Add "my email address"
  ObjMail.Display

End Sub

Since both PowerUser and I have found our signatures in C:\Users\" & Environ("username") & "\AppData\Roaming\Microsoft\Signatures I suggest this is the standard location for any Outlook installation. Can this default be changed? I cannot find anything to suggest it can. The above code clearly needs some development but it does achieve PowerUser's objective of creating an email body containing an HTML table above a signature.

Tony Dallimore
  • 12,335
  • 7
  • 32
  • 61
  • I'm glad you found my post useful, but I'm looking for something more direct. A coworker pointed out that a user can insert the default signature manually by using the commandbar **Insert->Signatures->(first signature)**. How can I do this in code? I'm experimenting with Controls and Commandbars, but not making much progress. – PowerUser Jan 31 '12 at 20:33
  • I am not sure what you mean by "more direct". This code creates a table over a signature which is what you wanted. I agree its only a dummy table but I do not know where the actual table is to come from. – Tony Dallimore Jan 31 '12 at 23:09
3

Most of the other answers are simply concatenating their HTML body with the HTML signature. However, this does not work with images, and it turns out there is a more "standard" way of doing this.1

Microsoft Outlook pre-2007 which is configured with WordEditor as its editor, and Microsoft Outlook 2007 and beyond, use a slightly cut-down version of the Word Editor to edit emails. This means we can use the Microsoft Word Document Object Model to make changes to the email.

Set objMsg = Application.CreateItem(olMailItem)
objMsg.GetInspector.Display 'Displaying an empty email will populate the default signature
Set objSigDoc = objMsg.GetInspector.WordEditor
Set objSel = objSigDoc.Windows(1).Selection
With objSel
   .Collapse wdCollapseStart
   .MoveEnd WdUnits.wdStory, 1
   .Copy 'This will copy the signature
End With
objMsg.HTMLBody = "<p>OUR HTML STUFF HERE</p>"
With objSel
   .Move WdUnits.wdStory, 1 'Move to the end of our new message
   .PasteAndFormat wdFormatOriginalFormatting 'Paste the copied signature
End With 
'I am not a VB programmer, wrote this originally in another language so if it does not
'compile it is because this is my first VB method :P

Microsoft Outlook 2007 Programming (S. Mosher)> Chapter 17, Working with Item Bodies: Working with Outlook Signatures

Birdie
  • 274
  • 2
  • 14
2

I like Mozzi's answer but found that it did not retain the default fonts that are user specific. The text all appeared in a system font as normal text. The code below retains the user's favourite fonts, while making it only a little longer. It is based on Mozzi's approach, uses a regular expression to replace the default body text and places the user's chosen Body text where it belongs by using GetInspector.WordEditor. I found that the call to GetInspector did not populate the HTMLbody as dimitry streblechenko says above in this thread, at least, not in Office 2010, so the object is still displayed in my code. In passing, please note that it is important that the MailItem is created as an Object, not as a straightforward MailItem - see here for more. (Oh, and sorry to those of different tastes, but I prefer longer descriptive variable names so that I can find routines!)

Public Function GetSignedMailItemAsObject(ByVal ToAddress As String, _
                      ByVal Subject As String, _
                      ByVal Body As String, _
                      SignatureName As String) As Object
'================================================================================================================='Creates a new MailItem in HTML format as an Object.
'Body, if provided, replaces all text in the default message.
'A Signature is appended at the end of the message.
'If SignatureName is invalid any existing default signature is left in place.
'=================================================================================================================
' REQUIRED REFERENCES
' VBScript regular expressions (5.5)
' Microsoft Scripting Runtime
'=================================================================================================================
Dim OlM As Object               'Do not define this as Outlook.MailItem.  If you do, some things will work and some won't (i.e. SendUsingAccount)
Dim Signature As String
Dim Doc As Word.Document
Dim Regex As New VBScript_RegExp_55.RegExp       '(can also use use Object if VBScript is not Referenced)

Set OlM = Application.CreateItem(olMailItem)
With OlM
    .To = ToAddress
    .Subject = Subject
    'SignatureName is the exactname that you gave your signature in the Message>Insert>Signature Dialog
    Signature = GetSignature(SignatureName)
    If Signature <> vbNullString Then
'        Should really strip the terminal </body tag out of signature by removing all characters from the start of the tag
'        but Outlook seems to handle this OK if you don't bother.
        .Display                                'Needed.  Without it, there is no existing HTMLbody available to work with.
        Set Doc = OlM.GetInspector.WordEditor   'Get any existing body with the WordEditor and delete all of it
        Doc.Range(Doc.Content.Start, Doc.Content.End) = vbNullString 'Delete all existing content - we don't want any default signature
        'Preserve all local email formatting by placing any new body text, followed by the Signature, into the empty HTMLbody.
        With Regex
            .IgnoreCase = True                  'Case insensitive
            .Global = False                     'Regex finds only the first match
            .MultiLine = True                   'In case there are stray EndOfLines (there shouldn't be in HTML but Word exports of HTML can be dire)
            .Pattern = "(<body.*)(?=<\/body)"   'Look for the whole HTMLbody but do NOT include the terminal </body tag in the value returned
            OlM.HTMLbody = .Replace(OlM.HTMLbody, "$1" & Signature)
        End With ' Regex
        Doc.Range(Doc.Content.Start, Doc.Content.Start) = Body 'Place the required Body before the signature (it will get the default style)
        .Close olSave                           'Close the Displayed MailItem (actually Object) and Save it.  If it is left open some later updates may fail.
    End If ' Signature <> vbNullString
End With ' OlM
Set GetSignedMailItemAsObject = OlM
End Function

Private Function GetSignature(sigName As String) As String
Dim oTextStream As Scripting.TextStream
Dim oSig As Object
Dim appDataDir, Signature, sigPath, fileName As String
Dim FileSys As Scripting.FileSystemObject        'Requires Microsoft Scripting Runtime to be available
    appDataDir = Environ("APPDATA") & "\Microsoft\Signatures"
    sigPath = appDataDir & "\" & sigName & ".htm"
    Set FileSys = CreateObject("Scripting.FileSystemObject")
    Set oTextStream = FileSys.OpenTextFile(sigPath)
    Signature = oTextStream.ReadAll
    ' fix relative references to images, etc. in Signature
    ' by making them absolute paths, OL will find the image
    fileName = Replace(sigName, ".htm", "") & "_files/"
    Signature = Replace(Signature, fileName, appDataDir & "\" & fileName)
    GetSignature = Signature
End Function
Community
  • 1
  • 1
Neil Dunlop
  • 387
  • 3
  • 16
2

The existing answers had a few problems for me:

  1. I needed to insert text (e.g. 'Good Day John Doe') with html formatting where you would normally type your message.
  2. At least on my machine, Outlook adds 2 blank lines above the signature where you should start typing. These should obviously be removed (replaced with custom HTML).

The code below does the job. Please note the following:

  1. The 'From' parameter allows you to choose the account (since there could be different default signatures for different email accounts)
  2. The 'Recipients' parameter expects an array of emails, and it will 'Resolve' the added email (i.e. find it in contacts, as if you had typed it in the 'To' box)
  3. Late binding is used, so no references are required
'Opens an outlook email with the provided email body and default signature
'Parameters:
'  from: Email address of Account to send from.  Wildcards are supported e.g. *@example.com
'  recipients: Array of recipients.  Recipient can be a Contact name or email address
'  subject: Email subject
'  htmlBody: Html formatted body to insert before signature (just body markup, should not contain html, head or body tags)
Public Sub CreateMail(from As String, recipients, subject As String, htmlBody As String)
    Dim oApp, oAcc As Object
    
    Set oApp = CreateObject("Outlook.application")
    
    With oApp.CreateItem(0) 'olMailItem = 0
        'Ensure we are sending with the correct account (to insert the correct signature)
        'oAcc is of type Outlook.Account, which has other properties that could be filtered with if required
        'SmtpAddress is usually equal to the raw email address
        .SendUsingAccount = Nothing
        For Each oAcc In oApp.Session.Accounts
            If CStr(oAcc.SmtpAddress) = from Or CStr(oAcc.SmtpAddress) Like from Then
                Set .SendUsingAccount = oAcc
            End If
        Next oAcc
        If .SendUsingAccount Is Nothing Then Err.Raise -1, , "Unknown email account " & from
        For Each addr In recipients
            With .recipients.Add(addr)
                'This will resolve the recipient as if you had typed the name/email and pressed Tab/Enter
                .Resolve
            End With
        Next addr
        .subject = subject
        .Display 'HTMLBody is only populated after this line
        'Remove blank lines at the top of the body
        .htmlBody = Replace(.htmlBody, "<o:p>&nbsp;</o:p>", "")
        'Insert the html at the start of the 'body' tag
        Dim bodyTagEnd As Long: bodyTagEnd = InStr(InStr(1, .htmlBody, "<body"), .htmlBody, ">")
        .htmlBody = Left(.htmlBody, bodyTagEnd) & htmlBody & Right(.htmlBody, Len(.htmlBody) - bodyTagEnd)
    End With
    Set oApp = Nothing
End Sub

Use as follows:

CreateMail from:="*@contoso.com", _
    recipients:= Array("john.doe@contoso.com", "Jane Doe", "unknown@example.com"), _
    subject:= "Test Email", _
    htmlBody:= "<p>Good Day All</p><p>Hello <b>World!</b></p>"

Result:

Sample Outlook Email

Jeremy Morren
  • 615
  • 9
  • 23
1

Often this question is asked in the context of Ron de Bruin's RangeToHTML function, which creates an HTML PublishObject from an Excel.Range, extracts that via FSO, and inserts the resulting stream HTML in to the email's HTMLBody. In doing so, this removes the default signature (the RangeToHTML function has a helper function GetBoiler which attempts to insert the default signature).

Unfortunately, the poorly-documented Application.CommandBars method is not available via Outlook:

wdDoc.Application.CommandBars.ExecuteMso "PasteExcelTableSourceFormatting"

It will raise a runtime 6158:

enter image description here

But we can still leverage the Word.Document which is accessible via the MailItem.GetInspector method, we can do something like this to copy & paste the selection from Excel to the Outlook email body, preserving your default signature (if there is one).

Dim rng as Range
Set rng = Range("A1:F10") 'Modify as needed

With OutMail
    .To = "xxxxx@xxxxx.com"
    .BCC = ""
    .Subject = "Subject"
    .Display
    Dim wdDoc As Object     '## Word.Document
    Dim wdRange As Object   '## Word.Range
    Set wdDoc = OutMail.GetInspector.WordEditor
    Set wdRange = wdDoc.Range(0, 0)
    wdRange.InsertAfter vbCrLf & vbCrLf
    'Copy the range in-place
    rng.Copy
    wdRange.Paste
End With

Note that in some cases this may not perfectly preserve the column widths or in some instances the row heights, and while it will also copy shapes and other objects in the Excel range, this may also cause some funky alignment issues, but for simple tables and Excel ranges, it is very good:

enter image description here

David Zemens
  • 53,033
  • 11
  • 81
  • 130
  • This answer is a gem but is sort of off-topic. It would fit really well in this question, though https://stackoverflow.com/questions/18663127/paste-specific-excel-range-in-outlook – Marcucciboy2 Oct 22 '19 at 16:18
  • @Marcucciboy2 cheers, I added this answer on that old question also. – David Zemens Oct 22 '19 at 17:26
1

Need to add a reference to Microsoft.Outlook. it is in Project references, from the visual basic window top menu.

Private Sub sendemail_Click()

  Dim OutlookApp As Outlook.Application
  Dim OutlookMail As Outlook.MailItem

  Set OutlookApp = New Outlook.Application
  Set OutlookMail = OutlookApp.CreateItem(olMailItem)

  With OutlookMail
    .Display
    .To = email
    .Subject = "subject"

    Dim wdDoc As Object     ' Word.Document
    Dim wdRange As Object   ' Word.Range
    Set wdDoc = .GetInspector.WordEditor
    Set wdRange = wdDoc.Range(0, 0) ' Create Range at character position 0 with length of 0 character s.

    ' if you need rtl:
    wdRange.Paragraphs.ReadingOrder = 0 ' 0 is rtl , 1 is ltr

    wdRange.InsertAfter "mytext"
  End With

End Sub
Shimon Doodkin
  • 4,310
  • 34
  • 37
  • When I add _.Body = "x"_ the signature stops inserting and all the body has is _mytextx_. How do I add a body and keep the signature? – PowerUser Dec 19 '19 at 20:23
  • @PowerUser, the signature is inserted by default as the initial value. You can save it and add text before it. There are 3 editors. .Body contains plain text. .HTMLBody is html body, basically word converted to html. And there is .GetInspector.WordEditor which is the original word editor. Each editor is used by its way. If you replace the editor value the signature is replaced – Shimon Doodkin Dec 21 '19 at 06:44
1

Assuming that your signature has this line "Thank you." Now all you need to do is to replace "Thank you." with whatever you want. Note: This is case sensitive so you must use the exact case. "Thank you" is not as "Thank You"

myMail.HTMLBody = Replace(myMail.HTMLBody, "Thank you.", "Please find attached the file you needed. Thank You.")

Here's the full code:

Sub Emailer()
        'Assumes your signature has this line: "Thank you."
        Set outlookApp = New Outlook.Application
        Set myMail = outlookApp.CreateItem(olMailItem)
        myMail.To = "x@x.com"
        myMail.Subject = "Hello"
        myMail.Display
        myMail.HTMLBody = Replace(myMail.HTMLBody, "Thank you.", "Please find attached the file you needed. Thank You.")
        'myMail.Send
        
    End Sub
Chadee Fouad
  • 2,630
  • 2
  • 23
  • 29
  • It's a solid idea for most text snippets but it wouldn't connect to Outlooks' *default signature*, only a text string embedded in the VBA.It would work, but would mean regular updates to the VBA code whenever Marketing changes our email signatures. – PowerUser Feb 24 '22 at 22:34
  • You're right but the aim was to be super simple, especially if you have control over the signature. If you want it to be really error proof under any circumstances then you'll have to put a lot of code unfortunately. Perhaps it could me modified to read the first line of the signature then do the replace. In that case it should work always. – Chadee Fouad Feb 26 '22 at 21:38
1

Outlook adds the signature to the new unmodified messages (you should not modify the body prior to that) when you call MailItem.Display (which causes the message to be displayed on the screen) or when you access the MailItem.GetInspector property (in the older versions of Outlook prior to 2016) - you do not have to do anything with the returned Inspector object, but Outlook will populate the message body with the signature.

Once the signature is added, read the HTMLBody property and merge it with the HTML string that you are trying to set. Note that you cannot simply concatenate 2 HTML strings - the strings need to be merged. E.g. if you want to insert your string at the top of the HTML body, look for the "<body" substring, then find the next occurrence of ">" (this takes care of the <body> element with attributes), then insert your HTML string after that ">".

Outlook Object Model does not expose signatures at all.

On a general note, the name of the signature is stored in the account profile data accessible through the IOlkAccountManager Extended MAPI interface. Since that interface is Extended MAPI, it can only be accessed using C++ or Delphi. You can see the interface and its data in OutlookSpy (I am its author) if you click the IOlkAccountManager button.
Once you have the signature name, you can read the HTML file from the file system (keep in mind that the folder name (Signatures in English) is localized.
Also keep in mind that if the signature contains images, they must also be added to the message as attachments and the <img> tags in the signature/message body adjusted to point the src attribute to the attachments rather than a subfolder of the Signatures folder where the images are stored.
It will also be your responsibility to merge the HTML styles from the signature HTML file with the styles of the message itself.

If using Redemption (I am its author) is an option, you can use its RDOAccount object - it exposes ReplySignature and NewMessageSignature properties.
Redemption also exposes RDOSignature.ApplyTo method that takes a pointer to the RDOMail object and inserts the signature at the specified location correctly merging the images and the styles:

set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Drafts = Session.GetDefaultFolder(olFolderDrafts)
set   Msg = Drafts.Items.Add
Msg.To =   "user@domain.demo"
Msg.Subject  = "testing signatures"
Msg.HTMLBody = "<html><body>some <b>bold</b> message text</body></html>"
set Account = Session.Accounts.GetOrder(2).Item(1)   'first mail account
if  Not (Account  Is  Nothing)  Then
     set Signature = Account.NewMessageSignature
     if  Not (Signature  Is  Nothing)  Then
       Signature.ApplyTo Msg,  false   'apply at the bottom
     End If
End If
Msg.Send
Dmitry Streblechenko
  • 62,942
  • 4
  • 53
  • 78
0

Previously MailItem.GetInspector was a valid replacement for MailItem.Display.

This solution was lost. "Outlook adds the signature to the new unmodified messages (you should not modify the body prior to that) when you call MailItem.Display (which causes the message to be displayed on the screen) or when you access the MailItem.GetInspector property (in the older versions of Outlook prior to 2016) - you do not have to do anything with the returned Inspector object, but Outlook will populate the message body with the signature."

.GetInspector can be implemented differently:

Option Explicit

Sub GenerateSignatureWithoutDisplay()

Dim objOutlook As Outlook.Application
Dim objMail As Outlook.mailItem

Set objOutlook = Outlook.Application
Set objMail = objOutlook.CreateItem(olMailItem)

With objMail

    .subject = "Test email to generate signature without .Display"
    
    ' To get the signature
    ' .GetInspector  ' Previously a direct replacement for .Display
    '  Later this no longer generated the signature.
    '  No error so solution assumed to be lost.
    '  2022-06-22  Compile error: Invalid use of property
    
    ' 2022-06-22  Germ of the idea seen here
    '  https://stackoverflow.com/questions/72692114
    ' Dim signature As Variant  ' The lucky trick to declare as Variant
    ' signature = .GetInspector
    ' signature = .HtmlBody
    ' .HtmlBody = "Input variable information here" & "<br><br>" & signature
    
    ' After review of the documentation
    '  https://learn.microsoft.com/en-us/office/vba/api/outlook.mailitem.getinspector
    Dim myInspector As Outlook.Inspector
    Set myInspector = .GetInspector
    .HtmlBody = "Input variable information here" & "<br><br>" & .HtmlBody
    .Close olSave
    
End With

' To verify after the save the signature is in saved mail
'objMail.Display

End Sub
niton
  • 8,771
  • 21
  • 32
  • 52
  • Keep in mind that you cannot in general concatenate two well-formed HTML strings and expect a well formed HTML string back. The two must be merged. – Dmitry Streblechenko Jun 22 '22 at 20:55