def test_deleteprop_doesnotexists(message): tag = PROP_TAG(PT_STRING8, 0x6600) problems = message.DeleteProps([tag]) assert len(problems) == 1 assert problems[0].ulIndex == 0 assert PROP_ID(problems[0].ulPropTag) == PROP_ID(tag) assert problems[0].scode == MAPI_E_NOT_FOUND
def test_get(message): ids = message.GetIDsFromNames([MAPINAMEID(b'1234567890123456', MNID_ID, 20)], MAPI_CREATE) assert len(ids) == 1 assert PROP_ID(ids[0]) >= 0x8500 assert PROP_TYPE(ids[0]) == PT_UNSPECIFIED ids = message.GetIDsFromNames([MAPINAMEID(b'1234567890123456', MNID_ID, 20)], 0) assert len(ids) == 1 assert PROP_ID(ids[0]) >= 0x8500 assert PROP_TYPE(ids[0]) == PT_UNSPECIFIED
def test_createnewmulti(message): ids = message.GetIDsFromNames([MAPINAMEID(b'1234567890123456', MNID_ID, 10), MAPINAMEID(b'1234567890123456', MNID_ID,11)], MAPI_CREATE) assert len(ids) == 2 assert PROP_ID(ids[0]) >= 0x8500 assert PROP_ID(ids[1]) >= 0x8500 tag = ids[1] ids = message.GetIDsFromNames([MAPINAMEID(b'1234567890123456', MNID_ID, 11), MAPINAMEID(b'1234567890123456', MNID_ID,12)], MAPI_CREATE) assert len(ids) == 2 assert PROP_ID(ids[0]) >= 0x8500 assert PROP_ID(ids[1]) >= 0x8500 assert tag == ids[0]
def test_createnew2(message): ids = message.GetIDsFromNames([MAPINAMEID(b'1234567890123456', MNID_ID, 5)], MAPI_CREATE) assert len(ids) == 1 assert PROP_ID(ids[0]) >= 0x8500 assert PROP_TYPE(ids[0]) == PT_UNSPECIFIED tag = ids[0] ids = message.GetIDsFromNames([MAPINAMEID(b'1234567890123456', MNID_ID, 5)], MAPI_CREATE) assert len(ids) == 1 assert PROP_ID(ids[0]) >= 0x8500 assert PROP_TYPE(ids[0]) == PT_UNSPECIFIED assert tag == ids[0] ids = message.GetIDsFromNames([MAPINAMEID(b'1234567890123456', MNID_ID, 6)], MAPI_CREATE) assert len(ids) == 1 assert PROP_ID(ids[0]) >= 0x8500 assert PROP_TYPE(ids[0]) == PT_UNSPECIFIED assert tag != ids[0]
def test_hiearchyid(store, message): # get on an unsaved prop, returns not found props = message.GetProps([PR_EC_HIERARCHYID], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_EC_HIERARCHYID)) assert props[0].Value == MAPI_E_NOT_FOUND # must be present after save/reopen message.SaveChanges(0) hid = message.GetProps([PR_EC_HIERARCHYID], 0)[0].Value eid = message.GetProps([PR_ENTRYID], 0)[0].Value message = store.OpenEntry(eid, None, 0) # first prop to get is generated, loadObject did not happen, but should assert message.GetProps([PR_EC_HIERARCHYID], 0)[0].Value == hid
def test_recordkey(message): props = message.GetProps([PR_RECORD_KEY], 0) assert props[0] == SPropValue(PROP_TAG(PT_ERROR, PROP_ID(PR_RECORD_KEY)), MAPI_E_NOT_FOUND) message.SaveChanges(KEEP_OPEN_READWRITE) props = message.GetProps([PR_RECORD_KEY, PR_ENTRYID], 0) assert props[0].ulPropTag == PR_RECORD_KEY assert len(props[0].Value) == 48 assert props[0].Value == props[1].Value (id, att) = message.CreateAttach(None, 0) att.SetProps([SPropValue(PR_ATTACH_METHOD, ATTACH_EMBEDDED_MSG)]) sub = att.OpenProperty(PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_CREATE | MAPI_MODIFY) props = sub.GetProps([PR_RECORD_KEY, PR_ENTRYID, PR_SOURCE_KEY], 0) # Unsaved submessages have a source key but no record key or entryid assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_RECORD_KEY)) assert props[0].Value == MAPI_E_NOT_FOUND assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_ENTRYID)) assert props[1].Value == MAPI_E_NOT_FOUND assert props[2].ulPropTag == PR_SOURCE_KEY assert len(props[2].Value) == 22 sub.SaveChanges(0) att.SaveChanges(0) message.SaveChanges(0) att = message.OpenAttach(0, None, 0) sub = att.OpenProperty(PR_ATTACH_DATA_OBJ, IID_IMessage, 0, 0) props = sub.GetProps([PR_RECORD_KEY, PR_ENTRYID, PR_SOURCE_KEY], 0) # Saved submessages have a PR_SOURCE_KEY but no record key or entryid assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_RECORD_KEY)) assert props[0].Value == MAPI_E_NOT_FOUND assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_ENTRYID)) assert props[1].Value == MAPI_E_NOT_FOUND assert props[2].ulPropTag == PR_SOURCE_KEY assert len(props[2].Value) == 22
def test_subject_unicode(store, message): # Normalized subject not found if no subject is present normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PROP_TAG(PT_ERROR, PROP_ID(PR_NORMALIZED_SUBJECT_W)), MAPI_E_NOT_FOUND)] # Subject prefix is generated if it contains a maximum of 3 characters followed by a colon : message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test')]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re: ')] normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PR_NORMALIZED_SUBJECT_W, 'test')] # Prefix should be correctly calculated with characters that occupy more than 1 byte message.SetProps([SPropValue(PR_SUBJECT_W, '回复: japanese subject')]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, '回复: ')] normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PR_NORMALIZED_SUBJECT_W, 'japanese subject')] # Although the MAPI documentation states a space must be present after the colon (:) we allow that in our code: # Set short prefix 'Re:', should clash with longer 'Re: ' prefix later message.SetProps([SPropValue(PR_SUBJECT_W, 'Re:factor')]) subjects = message.GetProps([PR_SUBJECT_PREFIX_W, PR_NORMALIZED_SUBJECT_W], 0) assert subjects == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re:'),SPropValue(PR_NORMALIZED_SUBJECT_W, 'factor')] # If prefix is larger than 3 characters it won't be calculated and the normalized property will be equal to the subject. # If the prefix is manually set and equal to the beginning of the subject it will be removed from the normalized. message.SetProps([SPropValue(PR_SUBJECT_W, 'Heelverhaal: test')]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, '')] normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PR_NORMALIZED_SUBJECT_W, 'Heelverhaal: test')] message.SetProps([SPropValue(PR_SUBJECT_PREFIX_W, 'Heelverhaal: ')]) normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PR_NORMALIZED_SUBJECT_W, 'test')] # If the prefix is different than intial string of the subject, the normalized will be equal to the subject message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test'), SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')] normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PR_NORMALIZED_SUBJECT_W, 'Re: test')] # After forcing the prefix to be different, it won't be recalculated anymore message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test')]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')] # After a reload we calculate the prefix again message.SaveChanges(KEEP_OPEN_READWRITE) entryid = message.GetProps([PR_ENTRYID], 0) m2 = store.OpenEntry(entryid[0].Value, None, MAPI_MODIFY) m2.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test')]) prefix = m2.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re: ')] # And the original message after save changes will also recalculate the prefix message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test')]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re: ')] # If we delete the message the prefix should not be found anymore message.DeleteProps([PR_SUBJECT_W]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PROP_TAG(PT_ERROR, PROP_ID(PR_SUBJECT_PREFIX_W)), MAPI_E_NOT_FOUND)] # If we set it explicitly and then delete the subject, we'll keep the prefix message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test'), SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')] message.DeleteProps([PR_SUBJECT_W]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')] # If we delete the prefix and then set the subject it will be synced again. message.DeleteProps([PR_SUBJECT_W, PR_SUBJECT_PREFIX_W]) message.SetProps([SPropValue(PR_SUBJECT_W, 'Re:factor')]) prefix = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert prefix == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re:')]
def test_deleteprop_computed(message): problems = message.DeleteProps([PR_ENTRYID]) assert len(problems) == 1 assert problems[0].ulIndex == 0 assert PROP_ID(problems[0].ulPropTag) == PROP_ID(PR_ENTRYID) assert problems[0].scode == MAPI_E_COMPUTED
def test_plain(store, message): message.SetProps([SPropValue(PR_BODY, b'pr_body')]) props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PR_BODY assert props[0].Value == b'pr_body' assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_RTF_COMPRESSED)) assert props[1].Value == MAPI_E_NOT_FOUND assert props[2].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_HTML)) assert props[2].Value == MAPI_E_NOT_FOUND # Retest after reload message.SaveChanges(0) entryid = message.GetProps([PR_ENTRYID], 0)[0].Value message = store.OpenEntry(entryid, None, 0) props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PR_BODY assert props[0].Value == b'pr_body' assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_RTF_COMPRESSED)) assert props[1].Value == MAPI_E_NOT_FOUND assert props[2].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_HTML)) assert props[2].Value == MAPI_E_NOT_FOUND # Try two properties # BODY, RTF props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED], 0) assert props[0].ulPropTag == PR_BODY assert props[0].Value == b'pr_body' assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_RTF_COMPRESSED)) assert props[1].Value == MAPI_E_NOT_FOUND # BODY, HTML props = message.GetProps([PR_BODY, PR_HTML], 0) assert props[0].ulPropTag == PR_BODY assert props[0].Value == b'pr_body' assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_HTML)) assert props[1].Value == MAPI_E_NOT_FOUND # RTF, HTML props = message.GetProps([PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PR_RTF_COMPRESSED assert len(props[0].Value) > 0 assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_HTML)) assert props[1].Value == MAPI_E_NOT_FOUND # Try one property # BODY props = message.GetProps([PR_BODY], 0) assert props[0].ulPropTag == PR_BODY assert props[0].Value == b'pr_body' # RTF props = message.GetProps([PR_RTF_COMPRESSED], 0) assert props[0].ulPropTag == PR_RTF_COMPRESSED assert len(props[0].Value) > 0 # HTML props = message.GetProps([PR_HTML], 0) assert props[0].ulPropTag == PR_HTML assert len(props[0].Value) > 0
def test_html(store, message): message.SetProps([SPropValue(PR_HTML, b"pr_html_body")]) props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_BODY)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY bodystream = message.OpenProperty(PR_BODY, IID_IStream, 0, 0) assert bodystream.Read(4096) == b'pr_html_body' assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_RTF_COMPRESSED)) assert props[1].Value == MAPI_E_NOT_ENOUGH_MEMORY assert props[2].ulPropTag == PR_HTML assert props[2].Value == b'pr_html_body' # Retest after reload message.SaveChanges(0) entryid = message.GetProps([PR_ENTRYID], 0)[0].Value message = store.OpenEntry(entryid, None, 0) props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_BODY)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY bodystream = message.OpenProperty(PR_BODY, IID_IStream, 0, 0) assert bodystream.Read(4096) == b'pr_html_body' assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_RTF_COMPRESSED)) assert props[1].Value == MAPI_E_NOT_ENOUGH_MEMORY assert props[2].ulPropTag == PR_HTML assert props[2].Value == b'pr_html_body' # Try two properties # BODY == RTF props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_BODY)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY assert props[1].ulPropTag == PR_RTF_COMPRESSED assert len(props[1].Value) # BODY == HTML props = message.GetProps([PR_BODY, PR_HTML], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_BODY)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY assert props[1].ulPropTag == PR_HTML assert props[1].Value == b'pr_html_body' # RTF == HTML props = message.GetProps([PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_RTF_COMPRESSED)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY assert props[1].ulPropTag == PR_HTML assert props[1].Value == b'pr_html_body' # Try one property # BODY props = message.GetProps([PR_BODY], 0) assert props[0].ulPropTag == PR_BODY assert props[0].Value == b'pr_html_body' # RTF props = message.GetProps([PR_RTF_COMPRESSED], 0) assert props[0].ulPropTag == PR_RTF_COMPRESSED assert len(props[0].Value) > 0 # HTML props = message.GetProps([PR_HTML], 0) assert props[0].ulPropTag == PR_HTML assert props[0].Value == b'pr_html_body'
def test_rtf(store, message): rtfprop = message.OpenProperty(PR_RTF_COMPRESSED, IID_IStream, 0, MAPI_MODIFY | MAPI_CREATE) rtf = WrapCompressedRTFStream(rtfprop, 0) rtf.Write(b'pr_rtf_compressed') rtf.Commit(0) rtfprop.Seek(STREAM_SEEK_SET, 0) compdata = rtfprop.Read(4096) props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_BODY)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY bodystream = message.OpenProperty(PR_BODY, IID_IStream, 0, 0) assert bodystream.Read(4096) == b'pr_rtf_compressed\r\n' assert props[1].ulPropTag == PR_RTF_COMPRESSED assert props[1].Value == compdata assert props[2].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_HTML)) assert props[2].Value == MAPI_E_NOT_FOUND # Retest after reload message.SaveChanges(0) entryid = message.GetProps([PR_ENTRYID], 0)[0].Value message = store.OpenEntry(entryid, None, 0) props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_BODY)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY bodystream = message.OpenProperty(PR_BODY, IID_IStream, 0, 0) assert bodystream.Read(4096) == b'pr_rtf_compressed\r\n' assert props[1].ulPropTag == PR_RTF_COMPRESSED assert props[1].Value == compdata assert props[2].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_HTML)) assert props[2].Value == MAPI_E_NOT_FOUND # Try two properties # BODY == RTF props = message.GetProps([PR_BODY, PR_RTF_COMPRESSED], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_BODY)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY assert props[1].ulPropTag == PR_RTF_COMPRESSED assert len(props[1].Value) # BODY == HTML props = message.GetProps([PR_BODY, PR_HTML], 0) assert props[0].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_BODY)) assert props[0].Value == MAPI_E_NOT_ENOUGH_MEMORY assert props[1].ulPropTag == PR_HTML assert len(props[1].Value) > 0 # RTF == HTML props = message.GetProps([PR_RTF_COMPRESSED, PR_HTML], 0) assert props[0].ulPropTag == PR_RTF_COMPRESSED assert len(props[0].Value) > 0 assert props[1].ulPropTag == PROP_TAG(PT_ERROR, PROP_ID(PR_HTML)) assert props[1].Value == MAPI_E_NOT_FOUND # Try one property # BODY props = message.GetProps([PR_BODY], 0) assert props[0].ulPropTag == PR_BODY assert props[0].Value == b'pr_rtf_compressed\r\n' # RTF props = message.GetProps([PR_RTF_COMPRESSED], 0) assert props[0].ulPropTag == PR_RTF_COMPRESSED assert len(props[0].Value) > 0 # HTML props = message.GetProps([PR_HTML], 0) assert props[0].ulPropTag == PR_HTML assert len(props[0].Value) > 0
def test_subject_unicode(store, message): normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PROP_TAG(PT_ERROR, PROP_ID(PR_NORMALIZED_SUBJECT_W)), MAPI_E_NOT_FOUND)] # set short prefix 'Re:', should clash with longer 'Re: ' prefix later message.SetProps([SPropValue(PR_SUBJECT_W, 'Re:factor')]) subjects = message.GetProps([PR_SUBJECT_PREFIX_W, PR_NORMALIZED_SUBJECT_W], 0) assert subjects == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re:'),SPropValue(PR_NORMALIZED_SUBJECT_W, 'factor')] #subject prefix is synced, normalized is short message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test')]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re: ')] normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PR_NORMALIZED_SUBJECT_W, 'test')] #subject prefix is synced, normalized is same message.SetProps([SPropValue(PR_SUBJECT_W, 'Heelverhaal: test')]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, '')] normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PR_NORMALIZED_SUBJECT_W, 'Heelverhaal: test')] #subject prefix is still synced message.SetProps([SPropValue(PR_SUBJECT_W, 'Fw: test')]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject, [SPropValue(PR_SUBJECT_PREFIX_W, 'Fw: ')] #explicit is not synced anymore message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test'), SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')]) normalized = message.GetProps([PR_NORMALIZED_SUBJECT_W], 0) assert normalized == [SPropValue(PR_NORMALIZED_SUBJECT_W, 'test')] subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')] # once you've SetPropsed PR_SUBJECT_PREFIX_W, it's not touched anymore message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test')]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')] # and after a reload? message.SaveChanges(KEEP_OPEN_READWRITE) entryid = message.GetProps([PR_ENTRYID], 0) m2 = store.OpenEntry(entryid[0].Value, None, MAPI_MODIFY) m2.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test')]) subject = m2.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re: ')] # and orig message after save changes? message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test')]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re: ')] # what after deleting? message.DeleteProps([PR_SUBJECT_W]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PROP_TAG(PT_ERROR, PROP_ID(PR_SUBJECT_PREFIX_W)), MAPI_E_NOT_FOUND)] # explicit is not synced anymore message.SetProps([SPropValue(PR_SUBJECT_W, 'Re: test'), SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')] # what after deleting expliclit? message.DeleteProps([PR_SUBJECT_W]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Aap')] # no spaces, delete explicit prefix to sync again message.DeleteProps([PR_SUBJECT_W, PR_SUBJECT_PREFIX_W]) message.SetProps([SPropValue(PR_SUBJECT_W, 'Re:factor')]) subject = message.GetProps([PR_SUBJECT_PREFIX_W], 0) assert subject == [SPropValue(PR_SUBJECT_PREFIX_W, 'Re:')]