Forwarding Outlook Item as attachment and adding it to a category in the same VBA macro - vba

I have a macro that works for forwarding multiple Outlook items as attachments. I've pasted that below, but I want it to also add the forwarded message(s) to a category in outlook. So, not only would it forward the items that are in my inbox to the recipient, but it would also mark those items in a certain category. This way I could track which items I have forwarded using the macro. As it is now, it will show me the item has been forwarded on such and such date, but that may have been just a regular forwarding action. Hence the need for the macro to add the item to a specialized category.
Sub ForwardSelectedItems()
On Error Resume Next
Dim objItem As Outlook.MailItem
If Application.ActiveExplorer.Selection.Count = 0 Then
MsgBox ("No item selected")
Exit Sub
End If
For Each objItem In Application.ActiveExplorer.Selection
Set objMsg = objItem.Forward()
With objMsg
.Attachments.Add objItem, olEmbeddeditem
.Subject = "example"
.To = "example#example.com"
.Body = “”
.Send
End With
Next
Set objItem = Nothing
Set objMsg = Nothing
End Sub

The Categories property of the MailItem class allows to set a string representing the categories assigned to the Outlook item. Here is what MSDN states:
Categories is a delimited string of category names that have been assigned to an Outlook item. This property uses the character specified in the value name, sList, under HKEY_CURRENT_USER\Control Panel\International in the Windows registry, as the delimiter for multiple categories. To convert the string of category names to an array of category names, use the Microsoft Visual Basic function Split.
Note, you can use the Categories property of the Namespace class to get a Categories object that represents the set of Category objects available. This property represents the Master Category List, which is the set of Category objects that can be applied to Outlook items contained by the NameSpace object, and applies to all users of that namespace.
Also you may consider specifying the SaveSentMessageFolder for the mail item. The property allows to set a Folder object that represents the folder in which a copy of the e-mail message will be saved after being sent. So, you can easily recognize the auto-forwarded messages.

Related

How to search recipients of previously sent mail?

I have a code which checks the subject in my e-mail and warns me if I already sent an email with this subject. I experienced it would be smarter if it checks for the email address.
I tried substituting "subject" with "recipients" but without success.
Public Sub Application_ItemSend(ByVal thisItem As Object, Cancel As Boolean)
Dim ns As Outlook.NameSpace
Dim olfolder As MAPIFolder
Dim Item As Object
Set olApp = CreateObject("Outlook.Application")
Set olNs = olApp.GetNamespace("MAPI")
Set firstFolder = olNs.Folders("test#dk.com") ' name of my shared inbox
Set olfolder = firstFolder.Folders("sent items")
' iterate thru emails
For Each Item In olfolder.Items
' check subject content & date difference
If InStr(Item.Subject, thisItem.Recipients) And DateDiff("m", Item.SentOn, Now) < 1 Then
' added this part
If MsgBox("already sent", vbYesNo + vbQuestion + vbMsgBoxSetForeground, "Message Text Warning") = vbNo Then
' cancel the email
Cancel = True
End If
Exit For
End If
Just replace thisItem.Subject to thisItem.To
edit: Nathan_Sav said it all :) .Recipents property returns an array so you can loop through it, might as well use .To which will return all recipients separated by semicolon
edit2: note there are two other properties .cc and .bcc if you use them, whilst .Recipients array include all of them
Firstly, do not ever loop through all items in a folder - this is horribly inefficient. Use Items.Find with a restriction on the Subject and SentOn properties.
For the recipients, you can use a restriction on the To property, but keep in mind that on the MAPI level it translates to a restriction on the PR_DISPLAY_TO property, which may or may not include the actual email address. OOM does not create subrestrictions on the PR_MESSAGE_RECIPIENTS property. If using Redemption (I am its author) is an option, its version of RDOItems.Find/Restrict allows to specify Recipients, To, CC, BCC properties in a query and creates an appropriate restriction on the email address and name of the message recipients.
In the worst case you can restrict on the Subject and SentOn properties using Items.Find/FindNext or Items.Restrict, and then explicitly loop through the Recipients collection of the returned matches.

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.

Getting email body using vba code

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")

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.