Getting email body using vba code - vba

I am trying to get the email header and body inside my email in outlook using VBA. I am using the Application_NewMail() event handler to process that new mail has arrived, but I cannot figure out how to get the header and body from there.
This is the code that I have inside the Application_NewMail() event handler:
Private WithEvents myOlItems As Outlook.Items
Private Sub Application_NewMail()
Dim olApp As Outlook.Application
Dim oNS As NameSpace
Dim oFolder As MAPIFolder
Dim oNewMail As MailItem
Set olApp = Outlook.Application
Set oNS = GetNamespace("MAPI")
Set oFolder = oNS.GetDefaultFolder(olFolderInbox)
Set oNewMail = oFolder.Items.GetFirst
'This is the string that hold the mail body.
Dim mailBody As String
Dim mailArg() As String
MsgBox "New Mail!"
End Sub
This function is firing properly once I receive emails. I successfully get the messagebox to pop up. But I want to be able to read the mail body and header to insert into a database.
The actual database side of it I know how to do, but I am unsure how to get the header and body from the email. I have tried something like this:
Set olItem = ActiveExplorer.Selection.Item(1)
mailBody = oNewMail.Body
mailArg = Split(mailBody, vbLf)
'Check to see what is inside the body. We need to say Tank X: Y
MsgBox "This is line one " & mailArg(0) & "This is line two " & mailArg(1)
And I receive the error: Object variable or With block variable not set
Any help will be greatly appreciated.

You need to handle the NewMailEx event of the Application class instead. This event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The EntryIDsCollection string contains the Entry ID that corresponds to that item.
The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item.
The Outlook object model provides three main ways for working with item bodies:
Body.
HTMLBody.
The Word editor. The WordEditor property of the Inspector class returns an instance of the Word Document which represents the message body. So, you can use the Word object model do whatever you need with the message body.
Finally, you can use the PropertyAccessor object (see the corresponding property of the MailItem class) to read the "PR_TRANSPORT_MESSAGE_HEADERS" property value.
propertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001E")

Related

Outlook VBA to format text as HTML , and select a quick parts

I am completely clueless about VBA for outlook. I was hoping that I could record macros, but I see that its not possible.
So the issue I am having is that I receive close to 100 emails daily that arrive in plain text, and I always need to convert to HTML so that I can select a Quick Parts, then send the email.
Can this be automated with VBA?
The MailItem.BodyFormat property allows setting an OlBodyFormat constant indicating the format of the body text. For example:
Sub CreateHTMLMail()
'Creates a new email item and modifies its properties.
Dim objMail As MailItem
'Create mail item
Set objMail = Application.CreateItem(olMailItem)
With objMail
'Set body format to HTML
.BodyFormat = olFormatHTML
.HTMLBody = "<HTML><H2>The body of this message will appear in HTML.</H2><BODY>Type the message text here. </BODY></HTML>"
.Display
End With
End Sub
To handle incoming emails you may use the NewMailEx event of the Application class. The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item.

Move/Copy Mail Item To Folder with ItemAdd event generates Error

When I call Inbox_ItemAdd to make a copy of a Mail Item and then move the copy to a different folder, I get an error. The operation completes though.
When I debug the code it steps through without an error. It only errors when I remove the breakpoints. Finally, if I comment out:
moveMail.Move DestinationFolder
or
copied = MoveToFolder(copyMail, FolderName)
It creates volumes of copies in the originating folder. Its earliest entry point is from the ItemAdd event, so I'm wondering if
Set copyMail = olItem.Copy
results in kicking that event off again.
Here's my CopyToFolder and MoveToFolder functions:
Function MoveToFolder(olItem As Outlook.MailItem, FolderName As String) As Boolean
Dim objNS As Outlook.NameSpace
Dim Inbox As Outlook.Folder
Dim DestinationFolder As Outlook.Folder
Dim moveMail As Outlook.MailItem
Set objNS = Application.GetNamespace("MAPI")
Set DestinationFolder = objNS.Folders("MyMailBox#mailboxes.com").Folders(FolderName)
Set moveMail = olItem
moveMail.Move DestinationFolder
Set moveMail = Nothing
Set DestinationFolder = Nothing
Set Inbox = Nothing
Set objNS = Nothing
End Function
Function CopyToFolder(olItem As Outlook.MailItem, FolderName As String) As Boolean
Dim copyMail As Outlook.MailItem
Dim copied As Boolean
Set copyMail = olItem.Copy
copied = MoveToFolder(copyMail, FolderName)
CopyToFolder = copied
Set copyMail = Nothing
End Function
And I might call the CopyToFolder function by:
copyResult = CopyToFolder(olItem, "External")
Here is what MSDN states for the NewMailEx event:
The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item. Use this method with caution to minimize the impact on Outlook performance. However, depending on the setup on the client computer, after a new message arrives in the Inbox, processes like spam filtering and client rules that move the new message from the Inbox to another folder can occur asynchronously. You should not assume that after these events fire, you will always get a one-item increase in the number of items in the Inbox.
Looks like you have got some rules set up in Outlook. And these rules can be run against the item after the vent handler or asynchronously, i.e. when you try to call the Move method. Is it the case?
As a workaround you may consider getting the entry ID and try to get the received item after it's been processed by Outlook. Or just handle the ItemSend event instead.
Anyway, you may find the following series of articles helpful:
Outlook NewMail event unleashed: the challenge (NewMail, NewMailEx, ItemAdd)
Outlook NewMail event: solution options
Outlook NewMail event and Extended MAPI: C# example
Outlook NewMail unleashed: writing a working solution (C# example)

Track email through the draft/send/sent process

I'd like to follow the status of an email as it passes through the phases and folders of its life cycle, through "Drafts", "Outbox", and "Sent".
Of related interest is the ability to access existing emails to gather property info, such as sent time.
I've started with the included block of code. The Do Loop fails the moment the email is sent, because the variable disconnects from the email.
This causes the runtime error
The item has been moved or deleted.
The error number (Err.Number) is different every time, and I wonder what the design purpose is.
How can I stay connected to sending emails as they move through Drafts, Outbox, and Sent?
I see many mentions of the variable disconnecting from the mailitem, but no solutions that rely on the object hierarchy and avoid late-binding to address the issue. I thought perhaps there would be a GUID or UUID that identifies the message, but as indicated in the documentation, all properties such as EntryID can change if the item is moved, and such properties should not be relied on.
With deeper examination, this makes sense because an email is just a record in a database table. And if you duplicate/delete records between tables, the info might be the same or similar, but the record number probably won't be.
Also, that hits other nails: the same email can be sent multiple times, and also can be copied/pasted into different folders, and even different accounts. Now what's unique or not?
Aside from staying "connected" to a email, what properties or techniques can be used to ID one?
If there's no "proper" way to identify a mailitem as described, about the only thing I can think of is to use an existing or custom field, like the "Tag" property of OCX controls, to insert a UUID. Some companies use this sort of technique by putting a call/order/support number in the subject line to make then easier to track.
Dim outlobj As Outlook.Application
Dim mailobj As Outlook.MailItem
Set outlobj = Outlook.Application
Set mailobj = outlobj.CreateItem(olMailItem)
With mailobj
.Recipients.Add "wonderwoman#hallofjustice.com"
.Subject = "Invisible Jet Scheduled Maintenance Reminder"
.Body = "Your invisible jet need to be polished."
.Attachments.Add zipFilename
.Display
.Send
End With
Do
'next line fails due to email moving through Drafts, Outbox, & Sent
'notably, the VBA runtime Err.Num is different each time
'how do i keep the variable connected to a moving target?
If mailobj.Sent = False Then
Sleep 100
Else
MsgBox "The email has been sent."
'other code
Exit Do
End If
Loop
Create a class and add MailItem as the event enabled property of that class. Handle the events such as Open/Write/Send/Save etc. to have custom control on the e-mail life-cycle. EntryID is the unique property for each mail item.
Be cautious of the fact that Entry Id is only generated after the first save of the item and changes implicitly when user manually moves the item between folders.
Following a is an example to get you started:
Add a class Class1 like this
Option Explicit
Public WithEvents mItem As MailItem
Public id As String
Private Sub mItem_Open(Cancel As Boolean)
MsgBox "Mail item will be displayed."
id = mItem.EntryID
End Sub
Add a module with following code:
Option Explicit
Sub test()
Dim cls As New Class1
Dim id As String
Dim outlobj As Outlook.Application
Dim mailobj As Outlook.MailItem
Set outlobj = Outlook.Application
Set mailobj = outlobj.CreateItem(olMailItem)
Set cls.mItem = mailobj
With mailobj
.Recipients.Add "xx#yy.zz"
.Subject = "Test"
.Body = "Test Content of the e-mail."
.Save
.Display
id = cls.id '/ Store ID for later use.
Debug.Print id
End With
'/ Search that e-mail and display its body contents
Call Retrieve(id)
End Sub
Sub Retrieve(sEntryId As String)
Dim mailobj As Outlook.MailItem
Dim ns As NameSpace
Set ns = GetNamespace("MAPI")
Set mailobj = ns.GetItemFromID(sEntryId)
MsgBox mailobj.Body
End Sub
Run the sub test

Forward mail and add content to body (Outlook 2007, VBA)

Can anyone help me with editing the VBA-Code for the following Problem:
I want to forward e-mails with a specific subject to an specific E-Mail. In this process i want to add a text to the forwarded body.
Thank's for your help!
edit.
I have the code now, but it doesn't work properly. It sends the last E-Mail clicked on :(.
Sub Test(oMail As MailItem)
Dim MyItem As Outlook.MailItem
Dim obj_curitem As MailItem
Dim obj_newitem
Dim obj_Selection
Dim obj_curfolder
Dim obj_msgitems
Dim Forward As Object
If Err.Number = 0 Then
Set obj_Selection = Outlook.ActiveExplorer.Selection
If obj_Selection.Count > 0 Then
For Each obj_curitem In obj_Selection
strID = obj_curitem.EntryID
Set olNS = Application.GetNamespace("MAPI")
'Object auf einem neuen Item erstellen
Set obj_newitem = obj_curitem.Forward
With obj_curitem.Forward
.Forward = True
.SentOnBehalfOfName = "###" 'Deine Mailadresse
.Subject = "WG" & .Subject 'Betreff
.To = "###" 'Empfängermail
.BODY = "geprüft" & .BODY 'E-Mail Inhalt
.Send
End With
Next
End If
End If
End Sub
In general you will need to handle the NewMailEx event of the Application class where you can check out the Subject property and decide whether to forward the email or not. The Forward method of the Application class allows you doing so - it executes the Forward action for an item and returns the resulting copy as a MailItem object.
This NewMailEx event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The EntryIDsCollection string contains the Entry ID that corresponds to that item. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item.
The Outlook object model provides three main ways for working with item bodies:
Body.
HTMLBody.
The Word editor. The WordEditor property of the Inspector class returns an instance of the Word Document which represents the message body. So, you can use the Word object model do whatever you need with the message body.
See Chapter 17: Working with Item Bodies for more information.

Outlook 2013: select multiple emails and autoreply using template

I am trying to get this code to work.
I want to select multiple emails from my inbox and send a auto reply using a template.
I am getting a run-time error: Object variable or With Block variable not set.
Any help would be appreciated. Also I would like to add a msg box telling me how many items were sent.
Option Explicit
Sub ReplywithTemplate()
Dim Item As Outlook.MailItem
Dim oRespond As Outlook.MailItem
For Each Item In ActiveExplorer.Selection
' This sends a response back using a template
Set oRespond = Application.CreateItemFromTemplate("C:\Users\Accounting\AppData\Roaming\Microsoft\Templates\scautoreply.oft")
With oRespond
.Recipients.Add Item.SenderEmailAddress
.Subject = Item.Subject
' includes the original message as an attachment
.Attachments.Add Item
' use this for testing, change to .send once you have it working as desired
.Display
End With
On Error Resume Next
Next
Set oRespond = Nothing
End Sub
I have noticed the following lines of code:
For Each oRespond In ActiveExplorer.Selection
' This sends a response back using a template
Set oRespond = Application.CreateItemFromTemplate("C:\Users\Accounting\AppData\Roaming\Microsoft\Templates\scautoreply.oft")
With oRespond
You need to use a new variable for creating an auto-reply email from a template because the selected Outlook item is missed (replaced with a newly created one).
So, basically you can create an item from a template, add recipients from the selected Outlook item and call the Send method. Or you can use the Reply method of the selected item in Outlook, copy the required properties from a template and call the Send method. It is up to you which way is to choose.
Finally, you may find the Getting Started with VBA in Outlook 2010 article helpful.