'External incoming mail marked as draft and unsent
My question is similar to but not the same to the one below,
Mark a mailitem as sent (VBA outlook)
Basically, something (AV, bug in Outlook or Exchange or both), has modified hundreds of incoming (external emails) to a particular user as drafts and now appear as unsent. This means the user cannot reply to these messages and the suggested alternative of copying and pasting looks very unprofessional and confusing to the user's clients. Thankfully whatever was causing it stopped but the damage is done.
I need some way to modify the PR_MESSAGE_FLAGS programmatically. I am comfortable with VB script, VBA, VB.Net and even C#/C++ but I am coming up empty for how to do it.
Should it matter, the server is Exchange 2013 and client is Outlook 2010 or 2016 (32 or 64bit). The entire mailbox has been exported to PST and can be worked on offline if that helps. :)
Solution 1:[1]
Based on Dmitry's answer, here is the code that clones the old messages and marks them as sent so they can be replied to.
Only concern with it is that it seems to be breaking Conversations.
Dim mysession
Sub doFixDrafts()
log " Starting scan!"
Set mysession = CreateObject("Redemption.RDOSession")
mysession.Logon
Const sRootFolder = "\\Mailbox\Inbox"
Set oRootFolder = mysession.getfolderfrompath(sRootFolder)
'Set oRootFolder = mysession.PickFolder
doCleanupFolder oRootFolder, sRootFolder
log "Scan complete!!"
End Sub
Sub doCleanupFolder(oFolder, sFolder)
Dim c: c = 0
Dim i: i = 0
Dim tc: tc = Format(oFolder.Items.Count, "0000")
'Get start timestamp so we can report in at regular intervals...
Dim st: st = Now()
log "Checking... " & sFolder
Dim aMsgIDs()
'Make a list of 'unsent' messages
For Each Item In oFolder.Items
i = i + 1
If Not Item.Sent Then
c = c + 1
msgID = Item.EntryID
ReDim Preserve aMsgIDs(1 To c)
aMsgIDs(c) = msgID
c = Format(c, "0000")
End If
'Give update for large folders...
ct = Now()
td = DateDiff("s", st, ct)
If td > 15 Then
log c & "/" & i & "/" & tc & " so far..."
st = ct
End If
DoEvents
Next
c = Format(c, "0000")
log c & "," & tc & "," & sFolder
'Fix the corrupt messages
For m = 1 To CInt(c)
Set badMsg = mysession.GetMessageFromID(aMsgIDs(m))
sSender = badMsg.Sender
sSubject = badMsg.Subject
dSentDate = badMsg.SentOn
Set newMsg = oFolder.Items.Add("IPM.Note")
newMsg.Sent = True
badMsg.CopyTo (newMsg)
newMsg.Save
badMsg.Delete
Dim a As String
a = Format(m, "0000") & "," & sSender & ","
a = a & Chr(34) & sSubject & Chr(34) & ","
a = a & Chr(34) & dSentDate & Chr(34)
log a
DoEvents
Next m
For Each Item In oFolder.Folders
doCleanupFolder Item, sFolder & "\" & Item.Name
Next
End Sub
Sub log(s As String)
d = Format(Now(), "yyyy-mm-dd hh:mm:ss")
t = d & " " & s
Debug.Print t
Const logfile = "c:\temp\fixdrafts.txt"
Open logfile For Append As #1
Print #1, t
Close #1
End Sub
Solution 2:[2]
The answer is still the same - on the low (Extended MAPI) level, sent/unsent status (MSGFLAG_UNSENT
bit in the PR_MESSAGE_FLAGS
property) can only be changed before the item is saved for the very first time.
Outlook Object Model is subject to the same limitation of course, and the only way to create an item in the sent state is to create a PostItem
object - it is created in the sent state. You will then need to change the message class back to IPM.Note
and remove the icon related properties to make sure the item looks right.
Redemption (I am its author) lets you change the item's state (RDOMail.Sent
is read/write before the first call to Save
).
It should be pretty easy to create copies of existing unsent messages in the sent state - loop through the problematic messages (it is better to avoid using "for each" if you will be creating new items in the same folder - your "for each" loop will start picking up new messages. Loop through the messages first and store their entry ids in a list or array), create new item using Redemption (RDOFolder.Items.Add
), set the Sent
property to true (RDOMail.Sent = true
), open the problematic message by its entry ids (RDOSession.GetMessageFromID
), copy the problematic message into the new message using RDOMail.CopyTo(AnotherRDOMailObject)
, call RDOMail.Save
on the new message and RDOMail.Delete
on the old message.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Vic |
Solution 2 |