'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