Edit, send and save email to file system - vba

We currently have an email automatically created by Excel using VBA, with subject, recipient, message body with template text all filled in.
Sub CreateMail(Optional sFile As String = "")
'Create email to send to requestor with attachment sFile
'Declarations
Dim app As Outlook.Application
Dim msg As Outlook.MailItem
Dim send_to As Recipient
Dim send_tos As Recipients
'Initiations
Set app = CreateObject("Outlook.Application")
Set msg = app.CreateItem(olMailItem)
Set send_tos = msg.Recipients
Set send_to = send_tos.Add("receiver#email.com")
send_to.Type = 1
'Create message
With msg
.SentOnBehalfOfName = "sender#email.com"
.Subject = "This is the email subject"
.HTMLBody = "This is the email body" & vbCrLf
'Resolve each Recipient's name.
For Each send_to In msg.Recipients
send_to.Resolve
Next
If Len(sFile) > 0 Then
.Attachments.Add sFile
End If
.Display
End With
End sub
After making some manual changes to the email that is created, we'd like to send it and have a copy saved to a folder on the file system automatically (in addition to the usual sent folder in Outlook). Is there a way to do this all within Excel VBA?
I suspect it might be possible using Outlook VBA, however the folders are defined in Excel and we'd like to keep the code together in the one file.

What is your code for sending email? This works for me in an Excel VBA module:
Dim appOutLook As Outlook.Application
Dim MailOutLook As Outlook.MailItem
Set appOutLook = CreateObject("Outlook.Application")
Set MailOutLook = appOutLook.CreateItem(olMailItem)
With MailOutLook
.BodyFormat = olFormatRichText
.To = "email address"
.Subject = "Test"
.HTMLBody = "Test " & Now
.DeleteAfterSubmit = True 'to not retain in sent folder
.Display
.SaveAs "C:\filepath\Test.txt", 0
' .Send
End With
However, guess the real trick is allowing edit of the email before saving file. So far not seeing solution for that. Unfortunately the code execution does not pause while the message window is open. I was hoping for the pause since Office is supposed to be an integrated suite of apps - like opening a form in Access in dialog mode which does pause execution of code.

With code in Excel only, monitor the SentItems folder.
Utilizing Outlook Events From Excel
Confirm the mail from a unique ID.
The unique ID could be in the subject or body.
You could try saving the unique ID in PR_SEARCH_KEY. It is the same idea How, can get the exact sent Email from Sent Items folder? and How to uniquely identify an Outlook email as MailItem.EntryID changes when email is moved

Related

Control contents of email address fields

I want to send the body of a Word document as an email from MS Word 2016.
I want the user to select recipients from the address book. I want them to only be put in the BCC field.
How do I monitor the to/from/CC/BCC fields for changes, and then move those changes to BCC?
The documentation indicates the use of Inspectors, but nothing specific about accessing the contents of these fields.
I have two approaches:
open a new Outlook mail item, load the contents of the Word file to it, and then try to monitor the fields that way.
send directly from Word using the Quick Access Toolbar option "Send to Mail Recipient".
I don't know if that is an option based on what I was reading and if those fields are accessible via VBA.
Code example of what I have so far:
Sub SendDocumentInMail()
Dim bStarted As Boolean
Dim oOutlookApp As Outlook.Application
Dim oItem As Outlook.MailItem
On Error Resume Next
'Get Outlook if it's running
Set oOutlookApp = GetObject(, "Outlook.Application")
If Err <> 0 Then
'Outlook wasn't running, start it from code
Set oOutlookApp = CreateObject("Outlook.Application")
bStarted = True
End If
'Create a new mailitem
Set oItem = oOutlookApp.CreateItem(olMailItem)
With oItem
'Set the recipient for the new email
.To = "recipient#mail.com"
'Set the recipient for a copy
.CC = "recipient2#mail.com"
'Set the subject
.Subject = "New subject"
'The content of the document is used as the body for the email
.Body = ActiveDocument.Content
.Send
End With
If bStarted Then
'If we started Outlook from code, then close it
oOutlookApp.Quit
End If
'Clean up
Set oItem = Nothing
Set oOutlookApp = Nothing
End Sub
It seems you are interested in the SelectNamesDialog object which displays the Select Names dialog box for the user to select entries from one or more address lists, and returns the selected entries in the collection object specified by the property SelectNamesDialog.Recipients.
The dialog box displayed by SelectNamesDialog.Display is similar to the Select Names dialog box in the Outlook user interface. It observes the size and position settings of the built-in Select Names dialog box. However, its default state does not show Message Recipients above the To, Cc, and Bcc edit boxes.
The following code sample shows how to create a mail item, allow the user to select recipients from the Exchange Global Address List in the Select Names dialog box, and if the user has selected recipients that can be completely resolved, then send the mail item.
Sub SelectRecipients()
Dim oMsg As MailItem
Set oMsg = Application.CreateItem(olMailItem)
Dim oDialog As SelectNamesDialog
Set oDialog = Application.Session.GetSelectNamesDialog
With oDialog
.InitialAddressList = _
Application.Session.GetGlobalAddressList
.Recipients = oMsg.Recipients
If .Display Then
'Recipients Resolved
oMsg.Subject = "Hello"
oMsg.Send
End If
End With
End Sub

How to set Outlook From email address from Word VBA

I'm trying to use Word VBA to send a document to an email recipient. For the most part, it is not difficult. I have this code so far:
With oItem
'Set the recipient for the new email
.To = "person1#mail.com"
'Set the recipient for a copy
.CC = "ccperson#mail.com"
'Set the subject
.Subject = "Blah blah"
End With
My problem is that I have several sender email addresses configured in Outlook, and Outlook is picking the wrong one by default.
Is there a way to specify a sender email address using the method above? Needless to say, the intuitive code line for specifying a sender address (.From = me#wherever.com) does not work. Thank you.
UPDATE:
I finally got my code to work after modifying it using the suggestions from peakpeak and Dimitry below. My changes were
1) to include a reference to the Microsoft Outlook 16 object library so that I could get access to the Outlook.MailItem datatype. The mail would send fine with the code above (without the reference), but would always send with the wrong From address.
2) Declare the mail item as Outlook.MailItem. This seemed to enable the SentOnBehalfOfName field.
3) Used my desired From: email address in the SentOnBehalfOfName field.
Here is the working code:
Dim MAPIMailItem As Outlook.MailItem
Set MAPIMailItem = olkApp.CreateItem(olMailItem) 'Create a new mail message
With MAPIMailItem
.BodyFormat = olFormatPlain
.to = strTo
' SentOnBehalfOfName sets the From field on my machine,
' AFTER I declared MAPIMailItem as Outlook.MailItem
.SentOnBehalfOfName = "fromAddress#foo.com"
.Subject = strSubject
.body = strBody
.attachments.Add strAtt
'.send
.Display
End With
I use this code:
Dim WantedAccount as String ' Set to preferred account name
Set MAPISession = objOutlook.Application.Session 'Get the MAPI Outlook session
Set MAPIMailItem = objOutlook.CreateItem(olMailItem) 'Create a new mail message
With MAPIMailItem
For Each Account In MAPISession.Accounts
If Account = WantedAccount Then
.SendUsingAccount = Account
Exit For
End If
Next
If you are sending through an Exchange account, set the MailItem.SentOnBehalfOfName property (assuming you have the right to send on behalf of the specified mailbox). If you are sending through a POP3/SMTP account, set the MailItem.SendUsingAccount property.

Outlook Email created in VBA using a template converts to plain text when saved

Below is the code that I am running in ThisOutlookSession. The code is meant to check all incoming emails and if the email is from a certain email address and contains a specific string in the subject then a new email is created from a template and the triggering email is attached and the email is then sent out to a different email address. This portion all works fine.
Also to note I am using windows 10 and office 2016.
The problem that I am having is the email is converted to plain text unless it is displayed first. The template that I have created is saved as a HTML formatted message. I have tried adding lines such as
NewMsg.BodyFormat = olFormatHTML
NewMsg.save
But this doesn't seem to work as the email that is sent was still in the plain text format. If I add the following to that the message it basically works.
NewMsg.BodyFormat = olFormatRichText
NewMsg.save
NewMsg.BodyFormat = olFormatHTML
NewMsg.save
However the above block of code removes a lot of the formatting that was saved in my template such as different fonts/ font sizes.
Am I missing something about working with templates in VBA?
Also The problem that I am having with displaying the message first is two things. The obvious one is the flash that this causes because the message is briefly displayed. The second is my default signature is also added to the displayed message but I wanted to use a custom signature that I built into my template.
Here is my full code with sensitive information removed.
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
' default local Inbox
Set Items = objNS.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub Items_ItemAdd(ByVal item As Object)
On Error GoTo ErrorHandler
Dim Msg As Outlook.MailItem
Dim NewMsg As Outlook.MailItem
If TypeName(item) = "MailItem" Then
Set Msg = item
If Msg.SenderEmailAddress <> "example#example.com" Then GoTo Skip
If InStr(1, Msg.Subject, "Specific String") > 0 Then 'checks if subject contains the proper string
Set NewMsg = Application.CreateItemFromTemplate("Template Path")
Msg.Subject = Replace(Msg.Subject, "Old Subject", "New subject")
Msg.Save
NewMsg.HTMLBody = NewMsg.HTMLBody
NewMsg.Attachments.Add Msg
NewMsg.Recipients.Add("Example#Example.com")
NewMsg.Subject = Msg.Subject
NewMsg.Save
NewMsg.Send
End If
End If
Skip:
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
End Sub
Reset the HTMLBody property - that will force HTML format:
Msg.HTMLBody = Msg.HTMLBody

E-Mail body is lost when sending (outlook vba)

I'm trying to write a macro that sends an automatic notification to specific addresses before sending the original email. (Like a cc, without actually using cc.)
The content of the original formatted email, (including text, tables, and pictures,) should be copied and pasted into a new email which is then automatically sent. Everything works when I just display the message, but not when actually sending the email.
Here is my code:
Dim objMsg As Outlook.MailItem
Dim activeMailMessage As Outlook.MailItem
Dim BodyText As Object
' Create the message.
Set objMsg = Application.CreateItem(olMailItem)
'copy body of current item
Set activeMailMessage = ActiveInspector.CurrentItem
activeMailMessage.GetInspector().WordEditor.Range.FormattedText.Copy
'paste body into new email
Set BodyText = objMsg.GetInspector.WordEditor.Range
BodyText.Paste
'set up and send notification email
With objMsg
.To = "test#domain.com"
.Subject = "text"
.Send
End With
The text should be pasted into the body like this, but it won't paste:
With objMsg
.To = "test#domain.com"
.Subject = "test"
.body = bodytext.paste
.Send
End With
When I use .display the correct content is displayed. But when I send it directly (without first using .display), all of all information is lost and an empty email is sent. What can I do?
I could add a bcc in the original email to achieve the same result, but the original email does not always send, whereas this notification should be.
Your code is never actually setting the Body of the e-mail in the objMsg object. It is working when you have objMsg displayed because your interacting with the 'Inspector'.
If you directly set either the HTMLBody (if you want to retain formatting), or the Body property on objMsg then it will work as in the below example.
With objMsg
.HTMLBody = activeMailMessage.HTMLBody
.To = "test#domain.com"
.Subject = "text"
.Send
End With
Bob, regarding your question on images that are embedded within the e-mail being lost with the above approach. An alternate solution could be to use the MailItem's Copy method to create your new MailItem exactly as the original Item. This will also retain who the e-mail is being sent to you need to clear this to make sure only the intended recipients receive it.
Dim objMsg As Outlook.MailItem
Dim activeMailMessage As Outlook.MailItem
' Create the new message.
Set objMsg = Application.CreateItem(olMailItem)
' Assign the current item to activeMailMessage
Set activeMailMessage = ActiveInspector.CurrentItem
' Copy the current item to create a new message
Set objMsg = activeMailMessage.Copy
' Clear any existing recipients of the e-mail, as these will be retained in the Copy
While objMsg.Recipients.Count > 0
objMsg.Recipients.Remove 1
Wend
'set up and send notification email
With objMsg
.To = "test#domain.com"
.Subject = "text"
.Send
End With
This should retain your images and other attachments as they were in the original e-mail.
Try to call the Save method after calling the Paste method.

Outlook attachments send then move

how do I move the files once its been send out successfully to c:\complete
Can I limit the attachments to 10 attachments per email.
each file size is like 300kb
Option Explicit
Sub SendMessage(Optional AttachmentPath)
Dim objOutlook As Outlook.Application
Dim objOutlookMsg As Outlook.MailItem
Dim objOutlookRecip As Outlook.Recipient
Dim objOutlookAttach As Outlook.Attachment
Dim objOutlookFile As String
'// Attachment Path
AttachmentPath = "C:\Reports\"
'// Create the Outlook session.
Set objOutlook = CreateObject("Outlook.Application")
'// Create the message.
Set objOutlookMsg = objOutlook.CreateItem(olMailItem)
With objOutlookMsg
'// Add the To recipient(s) to the message.
Set objOutlookRecip = .Recipients.Add("omar")
Set objOutlookRecip = .Recipients.Add("omar")
objOutlookRecip.Type = olTo
'// Add the CC recipient(s) to the message.
Set objOutlookRecip = .Recipients.Add("omar")
objOutlookRecip.Type = olCC
'// Set the Subject, Body, and Importance of the message.
.Subject = "Reports"
.Body = "the Attached reports are complete !" & vbCrLf & vbCrLf
.Importance = olImportanceHigh '//High importance
'// Add attachments to the message.
objOutlookFile = Dir(AttachmentPath & "*.*")
Do While Len(objOutlookFile) > 0
.Attachments.Add AttachmentPath & objOutlookFile
objOutlookFile = Dir
Loop
'// Resolve each Recipient's name.
For Each objOutlookRecip In .Recipients
objOutlookRecip.Resolve
If Not objOutlookRecip.Resolve Then
objOutlookMsg.Display
End If
Next
'//.DeleteAfterSubmit = True
'//.Send
.Display
End With
Set objOutlookMsg = Nothing
Set objOutlook = Nothing
End Sub
It is not clear where you run the VBA macro code (Outlook, Word, Excel and etc.).
Anyway, there is no need to create a new Outlook Application instance in the Outlook VBA macro:
'// Create the Outlook session.
Set objOutlook = CreateObject("Outlook.Application")
Instead, you can use the Application property, for example:
'// Create the message.
Set objOutlookMsg = Application.CreateItem(olMailItem)
You can use the FileSystemObject for managing files on the disk. See Accessing Files with FileSystemObject for more information.
Also the Outlook object model provides the BeforeAttachmentAdd event for Outlook items which is fired before an attachment is added to an instance of the parent object. It provides an instance of the Attachment class to be added and the Cancel parameter which can be used to cancel the action. Just set to true to cancel the operation; otherwise, set to false to allow the Attachment to be added.
sorry one more question, can I stop outgoing email if there is no files in c:\reports\
The best way is to check the folder before runnig the VBA macro. You can use the FileSystemObject to get the job done.
The Application class from the Outlook object model provides the ItemSend event which is fired whenever an Microsoft Outlook item is sent, either by the user through an Inspector (before the inspector is closed, but after the user clicks the Send button) or when the Send method for an Outlook item, such as MailItem, is used in a program. It provides the item reference being sent and the Cancel parameter. If the event procedure sets the Cancel argument to true, the send action is not completed and the inspector is left open.
You can use both these events to check out whatever you need.
Finally, you may find the Getting Started with VBA in Outlook 2010 article in MSDN helpful.