Just as we have done with Excel and Word, we can use the win32ole library to automate various tasks in Microsoft Outlook. Let's take a look at how to create an new email message.
Of course, we'll want to require the win32ole library:
require 'win32ole'
Create an instance of the Outlook Application object:
outlook = WIN32OLE.new('Outlook.Application')
Outlook is a single-instance application, so if it is already running, calling the WIN32OLE.new method will behave the same as the WIN32OLE.connect method, returning the running instance.
To create a new item in Outlook, call the Application object's CreateItem method and pass it a numeric value that represents the type of item to create. Valid arguments include:
olMailItem = 0
olAppointmentItem = 1
olContactItem = 2
olTaskItem = 3
olJournalItem = 4
olNoteItem = 5
olPostItem = 6
So, to create a new email message (ie, MailItem), we call the CreateItem method with an argument of 0 (zero):
message = outlook.CreateItem(0)
This returns the newly-created mail item object. We'll proceed by setting values for this MailItem object's properties and calling some of its methods.
To define the subject line of the message, set its Subject value with a string:
message.Subject = 'Double-Header Today'
To define the message body, set the Body value to a string:
message.Body = 'This is the message body.'
Alternatively, for an HTML message body, set the HtmlBody value to an HTML-encoded string.
Define the recipient by setting the To property...
message.To = 'ted.williams@redsox.com'
...or call the Recipients.Add method one or more times:
message.Recipients.Add 'ted.williams@redsox.com'
message.Recipients.Add 'joe.dimaggio@yankees.com'
Got attachments to add? Call the Attachments.Add method one or more times, passing it the path and name of the attachment:
message.Attachments.Add('c:\my_folder\my_file.txt', 1)
The second argument, 1, indicates that this is an attached file, rather than a link to the original file.
You can save the unsent message in your Outbox by calling the Save method...
message.Save
This would then allow you to open and review the message before manually clicking the Send button.
Of course, you can send the message with the Send method:
message.Send
Note that when using the Send method, Outlook may display a security alert that forces the user -- after a forced pause of about five seconds -- to click 'Yes' to allow the message to be sent. I am unaware of a method for avoiding this alert dialog.
UPDATE: I have discovered, but not yet used, a free Outlook add-in from MAPILab that allows the end user to set Outlook security settings. And the related ($99) Security Manager claims to allow you to bypass the Outlook security alerts, with a single line of code. I can't recommend either solution, not having tried them, but mention them here for your information.
That about wraps our show for today. Would you like to see more about Automating Outlook with Ruby? As always, feel free to post a comment here or email me with questions, comments, or suggestions.
Thanks for stopping by!
27 comments:
I wonder how one can mine out the chosen default mail client ... I wouldn't want to start Outlook for someone who uses, say, Thunderbird.
Is that somewhere in the Registry?
Nice, nice job, here. Keep it up.
When executing the Send-method I get a message box with a warning that an application tries to send email automaticly and if I want to allow this.
Maybe this should also be handled?
Yeah I encountered the same thing. I tried to get around this using something like:
wsh = WIN32OLE.new('Wscript.shell')
wsh.AppActivate('Microsoft Office Outlook')
sleep(1)
wsh.SendKeys('{TAB}{TAB} {TAB}{TAB}{ENTER}')
sleep(7) # to wait for the timer
wsh.SendKeys('{TAB}{TAB}{ENTER}')
But there has got to be an easier way....
@revence:
See my new post here.
I hope that helps.
@christian & adam:
I should have included mention of this in my post, sorry. I don't know that it is possible to disable the security alert. I shall investigate further...
The line above has message.etc assigning to attachment, but it's not used in the example.
attachment = message.Attachments.Add('c:\my_folder\my_file.txt', 1)
Probably you had in mind to assign the folder to attachment then add it to .Add method.
any other reason to use it here?
cheers
walter
@walter:
Actually, there was no reason for me to assign to a variable. The line should have read:
message.Attachments.Add('c:\my_folder\my_file.txt', 1)
I have corrected this in the post. Thanks for calling that to my attention!
David
Hi.
Thanks for the article. Do you know if this script will work with Outlook Express(?)
-Katie
@Katie-
Unfortunately, Outlook Express does not expose its objects for COM/OLE automation, so this script could not be adapted for Outlook Express.
David
Thank you for this utility. saved my day. Just to build on this further, is there a way to run multiple instances of the same ruby script. I would like to use this for some testing purposes where I am sending say 10 mails every second.
any thoughts?
For Katie:
if your default email program is Outlook Express, you can get around the lack of COM support by calling a mailto: tag somewhere. Thus running Outlook Express.
As I recall, in python you can use the webbrowser module to call a mailto tag, then form the tag with all your data with string concatenation.
Not sure how to do the same in Ruby
however this approach should work for your case.
cheers
walter
For Katie:
Here's a followup example python script. Please anyone post back with a Ruby equivalent, I'd appreciate it ;)
#script uses mailto tag to make
#email for Outlook Express users
#returns in body are replaced with
#linefeeds to remove OE error
import webbrowser
username = raw_input("Type the user's username: ")
email = raw_input("Type the user's email address: ")
subject = "Payment is Due"
body = r"""Dear Valued Customer,
We have noticed that you owe us money, please pay us now $"%s".
Regards,
Customer Service Department
""" %(amount_owed)
# replace return with line feed
body = body.replace("\n","%0A")
#make email
uri = r"mailto:%(email)s?subject=%(subject)s&body=%(body)s" %{'email' : email, 'subject':subject, 'body':body}
#send email to outlook express
webbrowser.open(uri)
Hi,
really really usefull article for me. Do you know perhaps how i can access the outlook addressbook?
cheers -- jerik
@j.erik:
If you mean Outlook Contacts, see my new post about it here.
David
Hi,
thank for your useful outlook blogs.
I'm looking to find the hook for monitoring and filtering outlook mails. Basically, i'd like to watch and filter incoming emails (realtime) so i can apply rules on it (think procmail in *nix).
thank you and kind regards - botp
@david:
No, not the contacts, I meand the address book. (Shortcut on Outlook is : STRG + SHIFT + b)
I want to make an easier and better search. The one in outlook, takes me to long to query for persons...
cheers -- jerik
@jerik:
I have just posted a new article here, discussing the Outlook Address Books.
David
I have previously used a library called Redemption for bypassing the oh-so-irritating 'click confirm to send' dialog. I don't know how it would interface with Ruby, but I will have a go to see if it works.
http://www.dimastr.com/redemption/
David, do you happen to have any links to documentation on scripting Outlook with ruby? Google is turning up nothing (but this post here).
Jim-
Well, I have several articles here tagged "outlook".
Let me know if there's something specific you need that's not covered here, and I'll do what I can to help.
David
Beautiful. This is almost exactly what I was looking for.
Hey David,
I am a long time fan of this blog, and an amateur in Ruby :). After a long time I finally worked out how to copy an excel table/selected range to an outlook mail, along with the formatting of the table...Hope this code adds some value to others ;)... cheers!
...
$ws.Range("A1:C5").copy
outlook = WIN32OLE.new('Outlook.Application')
message = outlook.CreateItem(0)
message.To = abc@xyz.com
message.Subject = "Copy excel table test"
message.Display
word = WIN32OLE.connect('Word.Application')
message.HTMLBody =
''
word.Selection.TypeText "Hi All,"
word.Selection.TypeParagraph
word.Selection.TypeParagraph
word.Selection.TypeText "This test will copy the excel table here:"
word.Selection.TypeParagraph
word.Selection.TypeParagraph
word.Selection.PasteExcelTable false, false, false
word.Selection.WholeStory
word.Selection.Font.Name = 'Calibri' #whichever font you want
word.Selection.Font.Size = 11
''
sleep 2
message.save
PS: Any reviews or improvements are welcome, it'll add to my learning.
Just to add:
If you are using Outlook 2007, the above code is not able to insert text/table in the email directly, since 2007 doesn't create an instance of Word application (which 2003 does, it can be seen under task manager - processes). So you need to tweak it a li'l bit using outlook 2007's 'Inspector'and 'WordEditor', as follows:
...
message.Display
selec = outlook.ActiveInspector.WordEditor.Windows(1).Selection
message.HTMLBody =
''
selec.TypeText "Hi All,"
...
Note: I also observed that on using message.Send method in outlook 2007, the security pop-up "A program is trying to send email on your behalf" is not displayed, and the email is sent successfully. I didn't use any third party tool or dlls like 'ClickYes' or Redemption.
Any ideas?
Hi everybody,
I'm trying to modify the mail of the sender and of the reply. I just triend that :
outlook = WIN32OLE.new('Outlook.Application')
message = outlook.CreateItem(olMailItem)
message.Subject = subject
message.Body = body
message.To = user_to.mail
message.SenderEmailAddress = user_from.mail
message.Save
message.Send
because i don't see an other way to do it.
The problem is it gives me this error message :
OLE error code:4096 in Microsoft Office Outlook
Property is read-only.
HRESULT error code:0x80020009
Exception occurred.
I researched in the Outlook VB window and it's really read-only.
Does anybody know how to modify it anyway ? or an idea ?
Or if it's not possible, how to use the outlook of the user computer to have his mail?
Thank you in advance :)
Hi!
I found this article very helpful but ran into my own problem. I'm trying to move the draft copy created when I 'mail.Save' to a folder outside of Outlook. I can do this manually but haven't worked out a way to have it done in the block.
Thanks,
HP
@Anonymous:
Try calling the SaveAs() method on the MailItem object. This method takes two arguments: the path and filename, and an integer specifying the filetype.
olRTF = 1
olMSG = 3
olHTML = 5
msg.SaveAs('c:\temp\Message.htm', olHTML)
-David
Excellent blog - thanks.
Q: any idea if it's possible to do the same without having outlook running? Cheers
Great Article,
FYI if you want to disable the warnings, go to (options/truscenter/trustcenter settings/programmatic access) and check if there is a "Anti-Virus Status is VAlid" if not you should install an antivirus EG:Sophos. Once you do that and restart your Outlook,the Warnings will Go Away !!!
Post a Comment