Ryan posted an article about some changes we're making in Outlook 2007 SP2. The gist is we're changing Outlook's shutdown behavior to always shutdown regardless of whether there are other running applications using the Outlook Object Model. He's looking for feedback on the logic change, so be sure to send him your comments.
Dan asked if I could post some CDO sample code he was working on. This sample script demonstrates a few interesting things:
Ultimately, what this sample does is delete all Out Of Office related messages (rules and templates), and switch off Out Of Office. Be careful running this sample! It doesn't back up anything before it deletes the OOF messages. So be certain that's what you really want to do before you go running this sample against a production mailbox.
If you want to run this code on an Outlook 2007 machine, you'll need to have CDO installed: CDO Download. If you want to run it without any version of Outlook installed, you can use the MAPI/CDO download: MAPI/CDO Download.
' Deloof.vbs - This sample shows how to walk through hidden items in a mailbox and delete
' the OOF templates and turn off OOF.
' This is a sample and is not intended to be used in a production environment.
' This script needs to be run from a 32 bit command line using cscript on a box with CDO 1.21 installed.
' The account running the code needs permission to the mailbox it will access.
' 9/19/08 danba - changed sample to include 6 message class tests.
' 9/23/08 danba - changed logic for TDX OOF Rules - PidTagRuleMsgName may not always be set.
' 10/24/08 sgriffin - minor scrub to formatting
Private Function RunIt(sServerName, sMailbox) 'As Boolean
Dim objsession ' MAPI.Session
Dim objInbox ' MAPI.Folder
Dim objHidden ' MAPI.Messages
Dim objMsgFilter ' MAPI.MessageFilter
Dim objOneMessage ' MAPI.Message
Dim sMessageClass ' String ' Message Class of rule
Dim s_ptagRuleMsgProvider ' String ' Provider of rule
Dim s_ptagRuleMsgName ' String ' Rule name
Dim sFoundMessage ' String ' Holds a message describing what was found.
Dim bDelete ' Boolean ' Used to indicate if an item should be deleted.
Dim iHidden ' Integer ' Use to loop through hidden items
wscript.echo "Time: " & Now
Set objsession = CreateObject("MAPI.session")
objsession.Logon "", "", False, False, 0, True, sServerName & vbLf & sMailbox
wscript.echo "Login completed on mailbox " & sMailbox & " on server" & sServerName
Set objInbox = objsession.Inbox
wscript.echo "Looking at the Inbox"
Set objHidden = objInbox.HiddenMessages
wscript.echo "Looking at the Hidden Items"
' --- Now we have the Hidden messages Set. Let's work thru the Hidden Messages and delete the 'oof items'
For iHidden = objHidden.Count To 1 Step -1 ' Walk Hidden backward one time
bDelete = false
sDeleteMessage = ""
Set objOneMessage = objHidden.Item(iHidden)
sMessageClass = objOneMessage.Type
On Error Resume Next
s_ptagRuleMsgProvider = ""
s_ptagRuleMsgName = ""
s_ptagRuleMsgProvider = objOneMessage.Fields(&H65EB001E) ' PidTagRuleMsgProvider
s_ptagRuleMsgName = objOneMessage.Fields(&H65EC001E) ' PidTagRuleMsgName
sFoundMessage = "Class: """ & sMessageClass & """"
if s_ptagRuleMsgName <> "" Then sFoundMessage = sFoundMessage & " Name: """ & s_ptagRuleMsgName & """"
if s_ptagRuleMsgProvider <> "" Then sFoundMessage = sFoundMessage & " Provider: """ & s_ptagRuleMsgProvider & """"
' TODO: comment out line below if you don't wish to what was found
Wscript.echo " Found: " & sFoundMessage
If sMessageClass = "IPM.Rule.Message" Then
If s_ptagRuleMsgProvider = "Microsoft Exchange OOF Assistant" AND _
s_ptagRuleMsgName = "Microsoft.Exchange.OOF.InternalSenders.Global" Then
bDelete = true
If s_ptagRuleMsgProvider = "MSFT:TDX OOF Rules" Then
s_ptagRuleMsgName = "Microsoft.Exchange.OOF.AllExternalSenders.Global" Then
If sMessageClass = "IPM.Note.Rules.OofTemplate.Microsoft" Then
bDelete = true
If sMessageClass = "IPM.Note.Rules.ExternalOofTemplate.Microsoft" Then
If sMessageClass = "IPM.ExtendedRule.Message" Then
s_ptagRuleMsgName = "Microsoft.Exchange.OOF.KnownExternalSenders.Global" Then
If bDelete = true Then
objHidden.Item(iHidden).Delete ' TODO: Comment-out if testing
wscript.echo " Deleted: " & sFoundMessage
objsession.OutOfOffice = 0 ' Turn off OOF ' TODO: Comment-out if testing
Set objOneMessage = Nothing
Set objInbox = Nothing
Set objsession = Nothing
RunIt = True
If Wscript.Arguments.Count = 2 Then
sServerName = Wscript.Arguments(0)
sMailbox = Wscript.Arguments(1)
bRet = RunIt(sServerName, sMailbox)
Wscript.Echo "deloof.vbs usage: deloof.vbs <Exchange Server Name> <Mail Box>"
Wscript.Echo "example: cscript deloof.vbs MyServer email@example.com"
The October 2008 Release (build 22.214.171.1249) is live: http://www.codeplex.com/MFCMAPI
Better late than never right? I've been trying to refresh MFCMAPI every two months, but wasn't able to devote the time to it I would have liked with all the work I'm doing on the MAPI documentation refresh. I did need to get this release out the door though since the MAPI docs will be depending on it. This release is all about cleaning up the code. It's been a long time since I went through the whole project and got all nitpicky about comments and whitespace. :)
Which is not to say I didn't get some nice bug fixes and features added. Here's a partial change list - see the Issue Tracker on Codeplex for more details, or look at the code:
So - we've got customers who had been using the Exchange 2007 Transport Agent's OnRoutedMessage event as a place to rewrite From addresses. This broke in Exchange 2007 SP1 due to some tweaks we made to the transport pipeline to solve a variety of other issues. We've got a fix for this now in Exchange 2007 SP1 Rollup 4, which just released today:
RU4 introduces a new event: OnCategorizedMessage. This event is at the right place in the pipeline to do your From address rewriting. Enjoy!
[This is now documented here: http://msdn.microsoft.com/en-us/library/ff960604.aspx ]
We had a customer here who wondered why messages imported into MAPI using MIMEToMAPI always appeared as draft messages. This is because the default value of PR_MESSAGE_FLAGS includes the MSGFLAG_UNSENT flag. Now - if you know you want your messages to not appear as drafts, the thing to do here is to clear the MSGFLAG_UNSENT flag before saving the message.
But what if you're exporting messages from mailbox using MAPIToMIMEStm and importing them using MIMEToMAPI, and want to preserve the sent/unsent state across this conversion? One thing you could do is read the state during the export, save it off somewhere (perhaps as a header in the EML file), then use it to determine if the flag needs to be cleared.
Doable - but a bit of extra work. Turns out there's flag you can use in those functions that has nearly the same effect: CCSF_EMBEDDED_MESSAGE
Here's the documentation on the flag:
#define CCSF_EMBEDDED_MESSAGE 0x8000 // sent/unsent information is persisted in X-Unsent
When CCSF_EMBEDDED_MESSAGE is set, if PR_MESSAGE_FLAGS has the MSGFLAG_UNSENT flag set, add an X-Unsent header to the MIME message with a value of 1
When CCSF_EMBEDDED_MESSAGE is set, the resultant MAPI message will have MSGFLAG_READ set in PR_MESSAGE_FLAGS. In addition, if an X-Unsent header is found with a value of 1, the MSGFLAG_UNSENT flag is removed from PR_MESSAGE_FLAGS.
This flag may be used in Outlook 2003 and higher. The name of this flag reflects the way it originally was used, as a way to deal with embedded messages. It is no longer used in this fashion. If the side effect of setting MSGFLAG_READ is not desired, this flag should not be used. If this flag is not set, MIMEToMAPI will ignore any value in X-Unsent and MSGFLAG_UNSENT will be set in PR_MESSAGE_FLAGS. MAPIToMIMEStm will not write the X-Unsent header at all if the MSGFLAG_UNSENT flag is not set in PR_MESSAGE_FLAGS.