Showing posts with label outlook. Show all posts
Showing posts with label outlook. Show all posts

Friday, September 2, 2011

Automating Outlook with Ruby: Saving Mail Messages To Files

I've talked in the past about managing mail messages in your Inbox, and about saving email attachments to your hard drive. A reader recently asked about saving a mail message as a file on your hard drive.


This can be done by calling the MailItem's SaveAs() method. This method takes two arguments. The first argument is a string indicating the full path and filename to which you want to save the message. The second argument is an integer that indicates the file type.

Let's look at a brief example that saves an Inbox message as an HTML file:

require 'win32ole'

olHTML = 5
outlook = WIN32OLE.connect("Outlook.Application")
mapi = outlook.GetNameSpace("MAPI")
inbox = mapi.GetDefaultFolder(6)
msg = inbox.Items(2)
msg.SaveAs('c:\temp\message.htm', olHTML)

Further details on the SaveAs() method can be found here.
A full list of valid file type values can be found here.

That's all for now. Questions? Comments? Suggestions? Post a comment or send me an email.

Thanks for stopping by!

Sunday, January 13, 2008

RubyGarden Archives: Scripting Outlook

Editor's Note: Once upon a time, there was a website named RubyGarden.org, which contained many helpful links and articles. The website has recently dropped off the face of the earth. The following "Scripting Outlook" article was salvaged from the Google cache and is provided here in its entirety.



With some help of the the ScriptingExcel page and the Office helpfiles mentioned there a short script to list your Outlook messages. The script should be pretty easy to expand. One method that was really helpfull in figuring out what is possible is:

OLEObject.ole_methods

MarkJanssen

require 'win32ole'

myApp = WIN32OLE::new("outlook.Application")

# load Outlook OLE constants

class OutlookConst
end

WIN32OLE.const_load(myApp, OutlookConst)

p "OlMailItem = #{OutlookConst::OlMailItem}"

ns = myApp.GetNameSpace("MAPI")
#ns.Logon # uncomment for online usage
folders = ns.Folders

new_messages = 0

folders.each {
| folder |
puts "+" + folder.Name

begin
folder.Folders.each {
| folder |
# puts " " + folder.Name
if ["Inbox","Sent Items"].member? folder.Name
folder.Items.each {
| msg |
if msg['UnRead']
new_messages += 1
end
puts " From: " + msg['SenderName']
puts " Subject: " + msg['Subject']
}
end
}
rescue

puts " Unable to open"
end
}
puts "You have #{new_messages} new message(s)"

Glauber 2003-10-09:

* Here's a quick tip that would have saved me some time: When iterating over a list of Outlook items (e.g.: MailItems) in order to move or delete some of them, you must do so backwards (GetLast... GetPrevious... GetPrevious...). In other words, don't attempt to access an item that's after the one you deleted or moved.
* Here's another tip: there's no good way to find the From Internet email address of a message. Most times, creating a reply and extracting the first recipient for it will work, but sometimes not (it may give you an Exchange X.400 address instead of what you're looking for). Don't send the reply, discard it.


Thursday, December 6, 2007

Automating Outlook with Ruby: Saving File Attachments

A while back, we looked at accessing the Outlook Inbox and managing messages. A reader recently asked how to iterate over the messages and save file attachments to their hard drive. Specifically, they wanted to save only those file attachments that exceeded 500k in size.

In Outlook, a message (MailItem) object's file attachments are accessed via the Attachments collection:


message.Attachments.each do |attachment|
# Do something here
end

The Attachment object has few properties and methods, but one you will use is the FileName property, which returns the, uh, filename.

To save the attachment, call its SaveAsFile method, passing it a path and filename:

attachment.SaveAsFile("c:\\attachments\\#{attachment.FileName}")

The attachment object does not offer a method/property for determining the file size. If you were looking to save only files of a certain size, you could save the file, then check the saved file's size and delete it if necessary. This is not optimal, but it does the trick.

So, putting this all together, we'd have something like the following code which iterates over your Inbox messages and saves all attachments of 500,000 bytes or larger:

require 'win32ole'

outlook = WIN32OLE.new('Outlook.Application')
mapi = outlook.GetNameSpace('MAPI')
inbox = mapi.GetDefaultFolder(6)
inbox.Items.each do |message|
message.Attachments.each do |attachment|
filename = "c:\\attachments\\#{attachment.FileName}"
attachment.SaveAsFile(filename)
File.delete(filename) if File.size(filename) < 500000
end
end

That's our show for today. Questions? Comments? Suggestions? Post a comment here or send me an email.

Thanks for stopping by!

Digg my article

Tuesday, August 28, 2007

Automating Outlook with Ruby: Inbox & Messages

In response to my series on Automating Outlook with Ruby, several readers have asked about accessing the Inbox and managing messages.

We start by using the win32ole library to create a new instance (or connect to a currently running instance) of the Outlook application object:


require 'win32ole'
outlook = WIN32OLE.new('Outlook.Application')

Next we'll get the MAPI namespace:

mapi = outlook.GetNameSpace('MAPI')

To get a reference to the Inbox folder, call the MAPI object's GetDefaultFolder method, passing it the integer 6, which represents the Inbox folder:

inbox = mapi.GetDefaultFolder(6)

To get the Personal Folders object, call the MAPI object's Folders.Item method, passing it the name of the folder.

personal_folders = mapi.Folders.Item('Personal Folders')

To reference a subfolder, call the parent folder object's Folders.Item method, passing it the name of the folder.

baseball_folder = personal_folders.Folders.Item('Baseball')

You can get a count of a folder's unread items by calling the UnreadItemCount method:

puts "#{inbox.UnreadItemCount} unread messages"

A folder object's Items method returns a collection of message objects, which you can iterate over:

inbox.Items.each do |message|
# Your code here...
end

You can also pass the Items method a (1-based) index to retrieve a single message:

first_message = inbox.Items(1)

Once your code tries to access methods and properties of a Message object, an Outlook security dialog will prompt the user to allow access to Address Book entries. The user must click a checkbox to allow access and select a time limit between 1 and 10 minutes.

Message objects have dozens of methods/properties, including:

SenderEmailAddress
SenderName
To
Cc
Subject
Body

To see a complete list, you could call the ole_methods method, as explained here. So to view a sorted list of the Message object's methods and properties, we could do this:

methods = []
inbox.Items(1).ole_methods.each do |method|
methods << method.to_s
end
puts methods.uniq.sort

To delete a message, call its Delete method:

message.Delete

To move a message to another folder, call its Move method, passing it the folder object:

baseball_folder = personal_folders.Folders.Item('Baseball')
message.Move(baseball_folder)

So, if we wanted to check our Inbox and move all messages that contain 'Cardinals' in the subject line to our 'Baseball' folder, we could do something like this:

inbox.Items.Count.downto(1) do |i|
message = inbox.Items(i)
if message.Subject =~ /cardinals/i
message.Move(baseball_folder)
end
end

As reader Ana points out, we should use the Count and downto methods to ensure that our inbox.Items index stays in sync, even as we move messages out of the Inbox. Otherwise, we run the risk of a message being skipped when the message above it is moved or deleted.

That concludes our program for today. Feel free to post a comment here or send me email with questions, comments, or suggestions.

Digg my article

Sunday, August 26, 2007

Automating Outlook with Ruby: Address Books

We recently discussed working with Outlook Contacts. On a related note, a reader asked how to access the Outlook Address Books. So let's dive right in...

We start by using the win32ole library to create a new instance (or connect to a currently running instance) of the Outlook application object:


require 'win32ole'
outlook = WIN32OLE.new('Outlook.Application')

Next we'll get the MAPI namespace:

mapi = outlook.GetNameSpace('MAPI')

The MAPI object's Session.AddressLists method, when called without parameters, returns a collection of the various Address Books available to Outlook, such as "Contacts", "Personal Address Book", and "Global Address List". The following code iterates over this collection and prints the name of each available Address Book:

mapi.Session.AddressLists.each do |list|
puts list.Name
end

To work with a particular Address Book, call the MAPI object's Session.AddressLists method and pass it the name of the Address Book:

address_list = mapi.Session.AddressLists('Global Address List')

This returns a single AddressList object. Call this object's AddressEntries method to obtain a list of AddressEntry objects:

address_entries = address_list.AddressEntries

Upon executing the above line of code, an Outlook security dialog will prompt the user to allow access to Address Book entries. The user must click a checkbox to allow access and select a time limit between 1 and 10 minutes.

Once access to the Address Book entries has been granted, you can iterate over the AddressEntries collection and get the Name and Address for each entry, or only for entries that meet certain criteria:

address_entries.each do |address|
if address.Name =~ /Machiavelli/
name = address.Name
email_address = address.Address
end
end

To search for an Address, you could call the AddressEntries collection's Item method. This accepts an integer as a (1-based) index:

address_entry = address_entries.Item(27)

...but also accepts a text string:

address_entry = address_entries.Item("sinatra, f")

This seems to return only the first AddressEntry object that meets the text string criteria. If no AddressEntry meets the text criteria, it seems to return the closest item following. So don't assume that the object returned meets your search criteria -- check the Name and/or Address properties to be certain.

There you have it. As always, feel free to post a comment here or send me email with questions, comments, or suggestions.

Thanks for stopping by!

Digg my article

Wednesday, August 15, 2007

Automating Outlook with Ruby: Contacts

We've looked at sending email, working with calendar appointments, and creating and managing tasks with Outlook. Next we'll take a look at how to create new contacts and read contacts data from Outlook.

You know by now how this starts out: we'll use the win32ole library to create a new instance (or connect to a currently running instance) of the Outlook application object:


require 'win32ole'
outlook = WIN32OLE.new('Outlook.Application')

Next we'll get the MAPI namespace:

mapi = outlook.GetNameSpace('MAPI')

Creating a New Contact

To create a new contact, call the Outlook Application object's CreateItem method, passing it the number 2, which represents a Contact Item. This returns a new Contact object:

contact = outlook.CreateItem(2)

Then set values for various properties of the new Contact object:

contact.FullName = 'Stan Musial'
contact.CompanyName = 'St. Louis Cardinals'
contact.JobTitle = 'Hitter'
contact.BusinessTelephoneNumber = '(314)555-1234'
contact.Email1Address = 'stan_the_man@stlcardinals.com'

What properties are available to set? Dozens. To see a list, you could call contact.ole_methods, Google for it (Outlook Contact Properties), or use an OLE object browser.

When you've completed setting property values, call the Contact object's Save method:

contact.Save

Getting Existing Contacts Data

To obtain a collection of Contacts, call the MAPI object's GetDefaultFolder method, passing it the integer 10, which represents the Contacts folder. Then call the Items method on this object:

contacts = mapi.GetDefaultFolder(10).Items

You can now iterate over this collection of Contact objects, calling the methods/properties to get the data you need:

contacts.each do |contact|
puts contact.FullName
puts contact.Email1Address
puts contact.BusinessTelephoneNumber
end

For further information, check out these Microsoft TechNet articles:

Creating a New Contact in Microsoft Outlook
Exporting Contact Information

As always, feel free to post a comment here or send me email with questions, comments, or suggestions.

Thanks for stopping by!


Digg my article

Wednesday, July 18, 2007

Automating Outlook with Ruby: Tasks

In our last episode, we used Ruby to extract appointments data from the Outlook Calendar, delete an appointment, and create a new appointment. Today we'll look at managing Outlook Tasks with Ruby.

Getting Existing Tasks

As usual, we'll use the win32ole library to create a new instance (or connect to a currently running instance) of the Outlook application object:


require 'win32ole'
outlook = WIN32OLE.new('Outlook.Application')

Next we'll get the MAPI namespace:

mapi = outlook.GetNameSpace('MAPI')

Outlook consists of several Folder objects, including Inbox, Tasks, and Calendar. To get a folder object, call the MAPI object's GetDefaultFolder method, passing it an integer representing the folder to return. For the Tasks folder, this number is 13:

tasks = mapi.GetDefaultFolder(13)

The Tasks folder's Items method returns a collection of all tasks, which you can iterate over. The following code prints out some of the most-often used properties for each task:

for task in tasks.Items
puts task.Subject
puts task.Body
puts task.DueDate
puts task.PercentComplete
puts task.Status
puts task.Importance
puts task.LastModificationTime
end

The Status method/property returns an integer, representing one of the following values:

0 -- Not started
1 -- In progress
2 -- Complete
3 -- Waiting on someone else
4 -- Deferred

The Importance method/property returns an integer, representing one of the following values:

0 -- Low
1 -- Normal
2 -- High

Filtering Your Tasks Collection

You can filter your collection of Task items by calling the Items collection's Restrict method, passing it a filter string. The following code gets all 'Order Yankees World Series Tickets' tasks, and then deletes each one:

for task in tasks.Items.Restrict("[Subject] = 'Order Yankees World Series Tickets'")
task.Delete
end

Other possible filters include:

tasks.Items.Restrict("[Status] = 'Not started'")
tasks.Items.Restrict("[Importance] = 'High'")

As illustrated in the above example, to delete a Task, call its Delete method.

Creating New Tasks

To create a new task, call the Outlook Application object's CreateItem method, passing it the number 3, which represents a Task Item. This returns a new Task object:

task = outlook.CreateItem(3)

Then set values for various properties of the new Task object:

task.Subject = 'Send flowers to wife'
task.Body = 'Call flower shop and send roses.'
task.ReminderSet = true
task.ReminderTime = '7/19/2007 12:00 PM'
task.DueDate = '7/20/2007 12:00 PM'
task.ReminderPlaySound = true
task.ReminderSoundFile = 'C:\Windows\Media\Ding.wav'

When you've completed setting property values, call the Task object's Save method:

task.Save

Further details can be found in this Microsoft TechNet article.

As always, feel free to post a comment here or send me email with questions, comments, or suggestions.

Thanks for stopping by!


Digg my article

Saturday, July 14, 2007

Automating Outlook with Ruby: Calendar Appointments

In a previous article, we looked at how to automate Microsoft Outlook to create and send a new email message. This time around, we'll use Ruby to extract appointments data from the Outlook Calendar, delete an appointment, and create a new appointment.

As usual, we'll use the win32ole library to create a new instance (or connect to a currently running instance) of the Outlook application object:


require 'win32ole'
outlook = WIN32OLE.new('Outlook.Application')

Next we'll get the MAPI namespace:

mapi = outlook.GetNameSpace('MAPI')

Outlook consists of several Folder objects, including Inbox, Tasks, and Calendar. To get a folder object, call the MAPI object's GetDefaultFolder method, passing it an integer representing the folder to return. For the Calendar folder, this number is 9:

calendar = mapi.GetDefaultFolder(9)

The calendar folder's Items method returns a collection of all appointments, which you can iterate over. Each appointment object includes dozens of properties. The following code prints out six of the most-often used properties:

calendar.Items.each do |appointment|
puts appointment.Subject
puts appointment.Location
puts appointment.Start
puts appointment.Duration
puts appointment.End
puts appointment.Body
end

To delete an appointment, call its Delete method. For example, the following code locates an appointment based on its Subject value, then deletes it, if found:

calendar.Items.each do |appointment|
if appointment.Subject == 'Punch Bud Selig in the Nose'
appointment.Delete
end
end

To create a new appointment, call the Outlook Application object's CreateItem method, passing it the number 1, which represents a Calendar Item. This returns a new Appointment object:

appointment = outlook.CreateItem(1)

Then set values for various properties of the new Appointment object:

appointment.BusyStatus = 2
appointment.Start = '7/29/2007 11:00 AM'
appointment.Duration = 300
appointment.Subject = 'Baseball Hall of Fame Induction'
appointment.Body = 'Tony Gwynn and Cal Ripken Jr.'
appointment.Location = 'Cooperstown, NY'
appointment.ReminderMinutesBeforeStart = 15
appointment.ReminderSet = true

The BusyStatus value is an integer with the following possible values:

olFree = 0
olTentative = 1
olBusy = 2
olOutOfOffice = 3

The Duration value is an integer representing the appointment length in minutes.

For an all-day event, forget the Duration property and instead set the AllDayEvent property to true:

appointment.AllDayEvent = true

To make an appointment recurring, you'll want to work with the Appointment object's Recurrence child object. You get this object by calling the GetRecurrencePattern method:

recurrence = appointment.GetRecurrencePattern

Now you'll set the RecurrenceType to one of the following values:

0 -- To set an appointment that occurs each and every day.
1 -- To set an appointment that occurs on the same day each week.
2 -- To set an appointment that occurs on the same day each month.
5 -- To set an appointment that occurs on the same day each year.

So, for an appointment that occurs on this day and time (as defined in your Start property above) each week:

recurrence.RecurrenceType = 1

Next, we'll set the PatternStartDate property. This value needs to be on or before the Start value defined above:

recurrence.PatternStartDate = '8/6/2007'

Finally, we set the PatternEndDate property:

recurrence.PatternEndDate = '8/27/2007'

When you've completed setting property values, call the Appointment object's Save method:

appointment.Save

And there you have it. Further details can be found in this Microsoft TechNet article.

Questions? Comments? Suggestions? Post a comment here or send me email.

Thanks for stopping by!


Digg my article

Sunday, July 1, 2007

Automating Outlook with Ruby: Sending Email

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!


Digg my article