VBA Copy Email as .MSG to New Email - vba

I am new to using VBA and I've looked around trying to find a solution. I don't know if this is even possible but I'm going to try and see if anyone can come up with any ideas.
So when you go into Outlook and you right click on an email, you can select copy. When you create a new email and paste the email, the copied email gets attached as a .msg as an attached file.
I am trying to replicate this process. Right now my process is
Find email
InStr(olMail.Subject, "SUBJECT") <> 0
Display email
olMail.Display
Copy body and set text to strPaste
Buf.SetText(OlMail.Body)
Buf.PutInClipBoard
strPaste = Buf.GetText(1)
Create new email
MailItem = OlApp.CreateItem(0)
Paste body
.Body = strPaste
This works but it isn't as clean because there are other things that are going into a message and it would be better for the copied email to be attached to an email instead of copying the body text.
I also don't want to save the email as an .msg and then attach it because other people will be using the macro and it would be quite tedious to change the path of where the email gets saved for every individual.
Any suggestions would be great!

So when you go into Outlook and you right click on an email, you can select copy. When you create a new email and paste the email, the copied email gets attached as a .msg as an attached file.
I am trying to replicate this process.
When forwarding MailItem as Attachment, use olEmbeddeditem
Which the Outlook message format file (.msg) is a copy of the original message to the new message.
Example in vba would be
Option Explicit
Sub Example()
'// Declare variables
Dim Msg As Outlook.MailItem
Dim Item As Outlook.MailItem
' Select Item
If Application.ActiveExplorer.Selection.Count = 0 Then
MsgBox ("No Item selected")
Exit Sub
End If
For Each Item In Application.ActiveExplorer.Selection
Set Msg = Application.CreateItem(olMailItem)
With Msg
.Attachments.Add Item, olEmbeddeditem ' Attch Selected email
.Display
End With
Next
'// Clean up
Set Item = Nothing
Set Msg = Nothing
End Sub
Select the Email that you would like to copy as .msg to new Email, then run the code

Related

Edit, send and save email to file system

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

Change account settings in Outlook 2010 using VBA

I have a large number of forwarding email addresses which are all set to forward to the same email account. I find this is useful because if a business is hacked and my email address is stolen then I only have the change the email address for that business. For example, "amazon#mydomain.com", "ebay#mydomain.com" and "facebook#mydomain.com" would all be forwarded to "mailbox#mydomain.com".
When I want to send an email to the business, I have to go into Outlook and change the account set up to have the forwarding email address as the email address. I find this a nuisance. I know I can change who the email is from when I write it, but then the recipient sees "J Smith on behalf of newaddress#mydomain.com". I would rather it just showed the address I am using in the from field, as it does if I go into the account set up and change the email address there.
It would be nice to have a macro set up which asked me which email address I wanted to use and then sent the email for me. I have looked up how to change email account details in VBA, but it looks as if the details are all read-only. Is there a way to change my "from" email address cleanly? Or even setting up a new email account in VBA and deleting it immediately after sending it?
Try creating a userform with a combobox and a button on it. Load all your available accounts into the combobox to be able to select from it:
Private Sub UserForm_Initialize()
Dim acc As Account
For Each acc In ThisOutlookSession.Session.Accounts
Me.ComboBox1.AddItem acc.UserName
Next acc
End Sub
Then add some code to the button that selects the proper account:
Dim objApp As Outlook.Application
Dim objMail As Outlook.MailItem
Set objApp = ThisOutlookSession.Application
Set objMail = objApp.CreateItem(olMailItem)
With objMail
.To = "lala#lala.com"
.CC = ""
.BCC = ""
.Subject = "Test"
.Body = "Test"
Dim i As Integer
For i = 1 To ThisOutlookSession.Session.Accounts.Count Step 1
If ThisOutlookSession.Session.Accounts.Item(i).UserName = Me.ComboBox1.Value Then
.SendUsingAccount = ThisOutlookSession.Session.Accounts.Item(i)
End If
Next i
.Display
End With
Maybe there is an event that is called when you are creating a new email, otherwise you have to add a button or something to bring the form up.
I had this exact same problem and ended up being able to solve it by installing Outlook Redemption and using the following script...
' Redemption code below. Must install Redemption to work.
' http://www.dimastr.com/redemption/faq.htm#14
Dim sItem, Tag
Set sItem = CreateObject("Redemption.SafeMailItem")
sItem.Item = oMailItem
Tag = sItem.GetIDsFromNames("{00020386-0000-0000-C000-000000000046}", "From")
Tag = Tag Or &H1E 'the type is PT_STRING8
sItem.Fields(Tag) = GetHashedReply(oMailItem)
Tag = sItem.GetIDsFromNames("{00020386-0000-0000-C000-000000000046}", "Sender")
Tag = Tag Or &H1E 'the type is PT_STRING8
sItem.Fields(Tag) = GetHashedReply(oMailItem)
sItem.Subject = sItem.Subject 'to trick Outlook into thinking that something has changed
sItem.Save
...where oMailItem is a normal Outlook MailItem that you can get with CreateItem() or get passed to you in the ItemSend() parameters.

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.

Retrieving Outlook Attachments in VBA from sent mail

What I am trying to get done is to have it so that on a few E-Mail templates we have at my job, when we drag and drop a certain Excel file to it, it will select and copy a range of that Excel file into the body of the email. My only question, as I've looked everywhere and all the code I've found seems to be for emails that are being received, not written, is how do I access:
The attachments in an email that I am writing
The body of the E-Mail I am writing
I'm sure I can get the code for everything else I want once I can get the attachments for the current Email.
Before any mentions "just record the macro and see how outlook does it" for some reason my outlook does not have a "record macro" item anywhere, as that was my first go-to as well.
how do I access: The attachments in an email that I am writing The
body of the E-Mail I am writing
Here is a very basic example. I have not done any error handling but I am sure you can take care of it.
Let's say the email that you are writing looks like this
All you need is this code
Sub Sample()
Dim NewMail As MailItem, oInspector As Inspector
Set oInspector = Application.ActiveInspector
'~~> Get the current open item
Set NewMail = oInspector.CurrentItem
With NewMail
Debug.Print .To
Debug.Print .subject
Debug.Print .Body
AttchCount = .Attachments.Count
If AttchCount > 0 Then
For I = 1 To AttchCount
'~~> Print Attachment names
Debug.Print .Attachments.Item(I).DisplayName
Next I
End If
End With
End Sub
Output

Force the `Recipients` object to update when the To: text box has been edited

I sort recipients when composing an email.
If I have 3 recipients (for example), run the sort macro, and then remove a recipient from the To: text box, running the macro a second time causes the removed recipient to re-appear. When I step through the macro on the second run, I can see that both .CurrentItem.To and the Recipients object still have all 3 recipients.
It is intermittent. Is there any way to force the Recipients object to update when the To: text box has been edited?
I can't find anything in the Outlook VBA documentation and trial and error has proved fruitless.
Code excerpt:
Public Sub SortRecipients()
With Application.ActiveInspector
If TypeOf .CurrentItem Is Outlook.MailItem Then
Debug.Print "Before: "
Debug.Print "To: " & .CurrentItem.To
Debug.Print "# of recipients: " & .CurrentItem.Recipients.Count
' Force an update if recipients have changed (DOESN'T HELP)
.CurrentItem.Recipients.ResolveAll
Set myRecipients = .CurrentItem.Recipients
' Create objects for To list
Dim myRecipient As recipient
Dim recipientToList As Object
Set recipientToList = CreateObject("System.Collections.ArrayList")
' Create new lists from To line
For Each myRecipient In myRecipients
recipientToList.Add myRecipient.Name
Next
' Sort the recipient lists
recipientToList.Sort
' Remove all recipients so we can re-add in the correct order
While myRecipients.Count > 0
myRecipients.Remove 1
Wend
' Create new To line
Dim recipientName As Variant
For Each recipientName In recipientToList
myRecipients.Add (recipientName)
Next recipientName
.CurrentItem.Recipients.ResolveAll
End If
End With
End Sub
Steps to reproduce:
Add 4 recipients to the "To" line of a new email in Outlook 2007 (click "Check Names" to resolve the addresses.)
Run the SortRecipients macro. (Recipients are now sorted)
Delete one recipient, re-run the SortRecipients macro.
After doing this, I still have 4 recipients (the deleted one returns).
You can (and should) add an Option Explicit, Outlook would have told you that myRecipients was not declared at the begining of your code.
I added:
Dim myRecipients As Recipients
[EDIT] That wasn't enough to get the To field refreshed. I tried several things but eventually, i added a .CurrentItem.Save instead of your try of .CurrentItem.Recipients.ResolveAll
I think i made it work this way on my Outlook 2007.