|
|
I noticed something strange when testing my Outlook Add-in
If I create a new email in Outlook 2003 and start to type some email address, a blue drop-down appears and helps me to complete the address.
Sometimes it suggests only email address without display name, i.e. sdsdfs[ at ]dfdf.com instead of say John Smith <sdsdfs[ at ]dfdf.com>
If I select the address from email, it appears that Outlook treats these addresses differently.
If I look at recipients table using Outlook Spy, I can see recipients email address only in PR_DISPLAY_NAME, PR_RECIPIENT_DISPLAY_NAME and strange tag 0x6001 (0x6001001E)
PR_EMAIL_ADDRESS is not found
I thought PR_EMAIL_ADDRESS is always present
Should I use PR_DISPLAY_NAME if PR_EMAIL_ADDRESS is not found?
Thanks
|
|
Have you tried saving the email before looking for PR_EMAIL_ADDRESS?
-- Ken Slovak [MVP - Outlook] http://www.slovaktech.com Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003 Reminder Manager, Extended Reminders, Attachment Options http://www.slovaktech.com/products.htm
"Slava Barouline" <slavadotbarouline[ at ]recruitmentsystemsdotcomdotau> wrote in message news:u8lcQqvpGHA.2148[ at ]TK2MSFTNGP03.phx.gbl...
[Quoted Text] >I noticed something strange when testing my Outlook Add-in > > If I create a new email in Outlook 2003 and start to type some email > address, a blue drop-down appears and helps me to complete the address. > > Sometimes it suggests only email address without display name, i.e. > sdsdfs[ at ]dfdf.com instead of say John Smith <sdsdfs[ at ]dfdf.com> > > If I select the address from email, it appears that Outlook treats these > addresses differently. > > If I look at recipients table using Outlook Spy, I can see recipients > email address only in PR_DISPLAY_NAME, PR_RECIPIENT_DISPLAY_NAME and > strange tag 0x6001 (0x6001001E) > > PR_EMAIL_ADDRESS is not found > > I thought PR_EMAIL_ADDRESS is always present > > Should I use PR_DISPLAY_NAME if PR_EMAIL_ADDRESS is not found? > > Thanks > > >
|
|
Yes, not much difference
"Ken Slovak - [MVP - Outlook]" <kenslovak[ at ]mvps.org> wrote in message news:O2Axnu0pGHA.148[ at ]TK2MSFTNGP04.phx.gbl...
[Quoted Text] > Have you tried saving the email before looking for PR_EMAIL_ADDRESS? >
|
|
Well, here at least until I save the email or send it there is nothing in the Recipients table when I open the item using the IMessage button in OutlookSpy. Once I do that I have PR_EMAIL_ADDRESS no matter whether the suggestion was just email address or name + email address. I don't have that strange property you mention.
I tested this on a Exchange profile, is that similar to yours or are you using only a PST file?
If the display name property gives you what you want then use it.
-- Ken Slovak [MVP - Outlook] http://www.slovaktech.com Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003 Reminder Manager, Extended Reminders, Attachment Options http://www.slovaktech.com/products.htm
"Slava Barouline" <slavadotbarouline[ at ]recruitmentsystemsdotcomdotau> wrote in message news:OIRSqUUqGHA.3484[ at ]TK2MSFTNGP04.phx.gbl...
[Quoted Text] > Yes, not much difference > > "Ken Slovak - [MVP - Outlook]" <kenslovak[ at ]mvps.org> wrote in message > news:O2Axnu0pGHA.148[ at ]TK2MSFTNGP04.phx.gbl... >> Have you tried saving the email before looking for PR_EMAIL_ADDRESS? >> > >
|
|
I do MailItem.Save in the code, but it dosn't seem to help.
If I press button in OutlookSpy, it works OK - I can see PR_EMAIL_ADDRESS fine.
Maybe doing MailItem.Save is not enough?
Sometimes popup has only display name and no email address - it's worse as I cannot use display name as email address.
I have Exchange profile
"Ken Slovak - [MVP - Outlook]" <kenslovak[ at ]mvps.org> wrote in message news:%23BO22KbqGHA.956[ at ]TK2MSFTNGP03.phx.gbl...
[Quoted Text] > Well, here at least until I save the email or send it there is nothing in > the Recipients table when I open the item using the IMessage button in > OutlookSpy. Once I do that I have PR_EMAIL_ADDRESS no matter whether the > suggestion was just email address or name + email address. I don't have > that strange property you mention. > > I tested this on a Exchange profile, is that similar to yours or are you > using only a PST file? > > If the display name property gives you what you want then use it. >
|
|
Saving the item should be enough.
If you can see the property in OutlookSpy then it's there in the recipient entry in the recipients table.
Maybe it's the code used. You haven't shown a code sample, let's see that and see if anyone spots anything.
-- Ken Slovak [MVP - Outlook] http://www.slovaktech.com Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003 Reminder Manager, Extended Reminders, Attachment Options http://www.slovaktech.com/products.htm
"Slava Barouline" <slavadotbarouline[ at ]recruitmentsystemsdotcomdotau> wrote in message news:u3Y$OzOxGHA.4200[ at ]TK2MSFTNGP04.phx.gbl...
[Quoted Text] >I do MailItem.Save in the code, but it dosn't seem to help. > > If I press button in OutlookSpy, it works OK - I can see PR_EMAIL_ADDRESS > fine. > > Maybe doing MailItem.Save is not enough? > > Sometimes popup has only display name and no email address - it's worse as > I cannot use display name as email address. > > I have Exchange profile
|
|
Just to remind the problem If I create a new email and start typing email address in To, Outlook suggests some emails in a popup Most emails look like Slava Barouline < email[ at ]com > , but sme have only address or display name The later fill recipients table incorrectly and don't get resolved even if I call MailItem.Save in my code I suspect Outlook delays resolving for some reason. If I save email in Outlook by pressing a button, emails get resolved and look OK in recipients table
Here it is (very scary code):
//Save before processing sent email: ......
//Save before accessing PR_BODY FMailItemToProcess.Save; ASubject := FMailItemToProcess.Subject; ABody := GetEmailBody;
....
//Get Recipients List AnEmailAddresses := GetRecipientEmailAddresses;
......
//Get emails from recipients table
function TMessageProcessor.GetRecipientEmailAddresses: TStringList; var OneMessage: IMessage; RecTable:IMAPITable; begin
RecTable:=nil; OneMessage :=IUnknown(FMailItemToProcess.MAPIOBJECT) as IMessage; OleCheck(OneMessage.GetRecipientTable(0,RecTable)); result := GetRecipientEmailAddressesFromTable(RecTable); RecTable := nil; OneMessage := nil;
end;
function TMessageProcessor.GetRecipientEmailAddressesFromTable(RecTable:IMAPITable): TStringList; type LTSPropTagArray = record cValues : ULONG; aulPropTag : array[0..3] of ULONG; end; const FPropTagArray : LTSPropTagArray = (cValues:4; aulPropTag:( PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_ADDRTYPE, PR_ENTRYID) ); var NRec :integer; ListRecTable:IMAPITable; RecCount:Ulong; lppRows:PSRowSet; EMailAddress, AnAddressType, ADisplayName: string; i: Integer; DistList: IDistList; AddrBook: IAddrBook; lpcbeid, ulObjectType: ULONG; lppeid: PENTRYID; ProcessInternalEmails, AskConfirmation: Boolean; begin
result := TStringList.Create; lppRows:=nil; ProcessInternalEmails := False; AskConfirmation := True;
OleCheck(RecTable.SetColumns([ at ]FPropTagArray,TBL_BATCH)); OleCheck(RecTable.GetRowCount(0,RecCount));
dmMain.LogLine('Found ' + IntToStr(RecCount) + ' recipient(s)');
if RecCount>0 then try
OleCheck(RecTable.QueryRows(RecCount,TBL_NOADVANCE,lppRows)); for Nrec:=0 to RecCount-1 do begin
// PR_EMAIL_ADDRESS is an optional property // therefore we must access it in a try except try AnAddressType := lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-2].Value.lpsza; if UpperCase(AnAddressType) = 'MAPIPDL' then begin dmMain.LogLine('Found private distribution list - trying to expand');
//!!! Get DistList AddrBook := GetAddressBook;
//The IAddrBook.OpenEntry method opens an address book entry //and returns a pointer to an interface that can be used //to access the entry.
lpcbeid := lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-1].Value.bin.cb; lppeid := LPENTRYID(lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-1].Value.bin.lpb);
DistList:=nil; ulObjectType:=8; //MAPI_DISTLIST
OleCheck(AddrBook.OpenEntry( lpcbeid, lppeid, [ at ]IID_IDistList, MAPI_BEST_ACCESS or MAPI_DEFERRED_ERRORS, ulObjectType, IUnknown(DistList)));
OleCheck(DistList.GetContentsTable(0,ListRecTable));
with GetRecipientEmailAddressesFromTable(ListRecTable) do for i:= 0 to Count - 1 do result.AddObject(Strings[i], Objects[i]);
DistList:=nil; ListRecTable := nil;
end
//Check Exchange email address type and ProcessInternalEmails setting else if (UpperCase(AnAddressType) = 'EX') and not dmMain.ProcessInternalEmails then begin
if ProcessInternalEmails then begin EMailAddress := lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-3].Value.lpsza; ADisplayName := lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-4].Value.lpsza; dmMain.LogLine('Recipient #' + IntToStr(Nrec + 1) + ' - email address: ' + EMailAddress + ' , display name: ' + ADisplayName); result.AddObject(EMailAddress, TStringObject.Create(ADisplayName)); end else begin EMailAddress := lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-3].Value.lpsza; ADisplayName := lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-4].Value.lpsza; dmMain.LogLine('Recipient #' + IntToStr(Nrec + 1) + ' - email address: ' + EMailAddress + ' , display name: ' + ADisplayName); dmMain.LogLine('Email address has Exchange address type');
//Manual processing if AskConfirmation and FIsManualProcessing then begin if MessageDlg(strExchangeRecipientAddressTypeConfirmation, mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin ProcessInternalEmails := True; result.AddObject(EMailAddress, TStringObject.Create(ADisplayName)); end else begin ProcessInternalEmails := False; dmMain.LogLine('Email address skipped'); end; AskConfirmation := False; end //Automatic processing - skip else dmMain.LogLine('Email address skipped');
end;
end else begin
//In case PR_EMAIL_ADDRESS is not found, use PR_DISPLAY_NAME instead ADisplayName := lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-4].Value.lpsza; try EMailAddress := lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-3].Value.lpsza; except dmMain.LogLine('Failed to read PR_EMAIL_ADDRESS, using PR_DISPLAY_NAME instead'); EMailAddress := ADisplayName; end;
dmMain.LogLine('Recipient #' + IntToStr(Nrec + 1) + ' - email address: ' + EMailAddress + ' , display name: ' + ADisplayName); result.AddObject(EMailAddress, TStringObject.Create(ADisplayName)); end;
except on e: Exception do dmMain.LogLine('Failed to read email address from recipient table row with error message: ' + e.Message); end; end;
except on e: Exception do dmMain.LogLine('Failed to retrieve recipients table with error message: ' + e.Message); end;
// Free each element in the pRows buffer FreeProws(lppRows);
end;
"Ken Slovak - [MVP - Outlook]" <kenslovak[ at ]mvps.org> wrote in message news:OdkEneSxGHA.3436[ at ]TK2MSFTNGP02.phx.gbl...
[Quoted Text] > Saving the item should be enough. > > If you can see the property in OutlookSpy then it's there in the recipient > entry in the recipients table. > > Maybe it's the code used. You haven't shown a code sample, let's see that > and see if anyone spots anything. > > -- > Ken Slovak > [MVP - Outlook] > http://www.slovaktech.com> Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003 > Reminder Manager, Extended Reminders, Attachment Options > http://www.slovaktech.com/products.htm> >
|
|
I don't see anything offhand but I'm no C++ programmer or even Extended MAPI programmer.
Have you tried resolving the recipients collection (Recipients.ResolveAll) and seeing if that helps?
One thing is if the email addresses are in the GAL and the email display name is not unique in the GAL then resolution will fail. In that case the alias must be fully qualified to resolve ("joe[ at ]foobar.com") and not just "joe".
-- Ken Slovak [MVP - Outlook] http://www.slovaktech.com Author: Absolute Beginner's Guide to Microsoft Office Outlook 2003 Reminder Manager, Extended Reminders, Attachment Options http://www.slovaktech.com/products.htm
"Slava Barouline" <slavadotbarouline[ at ]recruitmentsystemsdotcomdotau> wrote in message news:e8Fz9sxyGHA.2300[ at ]TK2MSFTNGP05.phx.gbl...
[Quoted Text] > Just to remind the problem > If I create a new email and start typing email address in To, Outlook > suggests some emails in a popup > Most emails look like Slava Barouline < email[ at ]com > , but sme have only > address or display name > The later fill recipients table incorrectly and don't get resolved even if > I call MailItem.Save in my code > I suspect Outlook delays resolving for some reason. > If I save email in Outlook by pressing a button, emails get resolved and > look OK in recipients table > > Here it is (very scary code): > > //Save before processing sent email: > ..... > > //Save before accessing PR_BODY > FMailItemToProcess.Save; > ASubject := FMailItemToProcess.Subject; > ABody := GetEmailBody; > > ... > > //Get Recipients List > AnEmailAddresses := GetRecipientEmailAddresses; > > ..... > > //Get emails from recipients table > > function TMessageProcessor.GetRecipientEmailAddresses: TStringList; > var > OneMessage: IMessage; > RecTable:IMAPITable; > begin > > RecTable:=nil; > OneMessage :=IUnknown(FMailItemToProcess.MAPIOBJECT) as IMessage; > OleCheck(OneMessage.GetRecipientTable(0,RecTable)); > result := GetRecipientEmailAddressesFromTable(RecTable); > RecTable := nil; > OneMessage := nil; > > end; > > function > TMessageProcessor.GetRecipientEmailAddressesFromTable(RecTable:IMAPITable): > TStringList; > type > LTSPropTagArray = > record > cValues : ULONG; > aulPropTag : array[0..3] of ULONG; > end; > const > FPropTagArray : LTSPropTagArray = (cValues:4; > aulPropTag:( > PR_DISPLAY_NAME, > PR_EMAIL_ADDRESS, > PR_ADDRTYPE, > PR_ENTRYID) > ); > var > NRec :integer; > ListRecTable:IMAPITable; > RecCount:Ulong; > lppRows:PSRowSet; > EMailAddress, AnAddressType, ADisplayName: string; > i: Integer; > DistList: IDistList; > AddrBook: IAddrBook; > lpcbeid, ulObjectType: ULONG; > lppeid: PENTRYID; > ProcessInternalEmails, AskConfirmation: Boolean; > begin > > result := TStringList.Create; > lppRows:=nil; > ProcessInternalEmails := False; > AskConfirmation := True; > > OleCheck(RecTable.SetColumns([ at ]FPropTagArray,TBL_BATCH)); > OleCheck(RecTable.GetRowCount(0,RecCount)); > > dmMain.LogLine('Found ' + IntToStr(RecCount) + ' recipient(s)'); > > if RecCount>0 then > try > > OleCheck(RecTable.QueryRows(RecCount,TBL_NOADVANCE,lppRows)); > for Nrec:=0 to RecCount-1 do > begin > > // PR_EMAIL_ADDRESS is an optional property > // therefore we must access it in a try except > try > AnAddressType := > lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-2].Value.lpsza; > if UpperCase(AnAddressType) = 'MAPIPDL' then > begin > dmMain.LogLine('Found private distribution list - trying to > expand'); > > //!!! Get DistList > AddrBook := GetAddressBook; > > //The IAddrBook.OpenEntry method opens an address book entry > //and returns a pointer to an interface that can be used > //to access the entry. > > lpcbeid := > lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-1].Value.bin.cb; > lppeid := > LPENTRYID(lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-1].Value.bin.lpb); > > DistList:=nil; > ulObjectType:=8; //MAPI_DISTLIST > > OleCheck(AddrBook.OpenEntry( > lpcbeid, > lppeid, > [ at ]IID_IDistList, > MAPI_BEST_ACCESS or MAPI_DEFERRED_ERRORS, > ulObjectType, > IUnknown(DistList))); > > OleCheck(DistList.GetContentsTable(0,ListRecTable)); > > with GetRecipientEmailAddressesFromTable(ListRecTable) do > for i:= 0 to Count - 1 do > result.AddObject(Strings[i], Objects[i]); > > DistList:=nil; > ListRecTable := nil; > > end > > //Check Exchange email address type and ProcessInternalEmails > setting > else if (UpperCase(AnAddressType) = 'EX') > and not dmMain.ProcessInternalEmails then > begin > > if ProcessInternalEmails then > begin > EMailAddress := > lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-3].Value.lpsza; > ADisplayName := > lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-4].Value.lpsza; > dmMain.LogLine('Recipient #' + IntToStr(Nrec + 1) + ' - email > address: ' + EMailAddress + ' , display name: ' + ADisplayName); > result.AddObject(EMailAddress, > TStringObject.Create(ADisplayName)); > end > else > begin > EMailAddress := > lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-3].Value.lpsza; > ADisplayName := > lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-4].Value.lpsza; > dmMain.LogLine('Recipient #' + IntToStr(Nrec + 1) + ' - email > address: ' + EMailAddress + ' , display name: ' + ADisplayName); > dmMain.LogLine('Email address has Exchange address type'); > > //Manual processing > if AskConfirmation and FIsManualProcessing then > begin > if MessageDlg(strExchangeRecipientAddressTypeConfirmation, > mtConfirmation, [mbYes, mbNo], 0) = mrYes then > begin > ProcessInternalEmails := True; > result.AddObject(EMailAddress, > TStringObject.Create(ADisplayName)); > end > else > begin > ProcessInternalEmails := False; > dmMain.LogLine('Email address skipped'); > end; > AskConfirmation := False; > end > //Automatic processing - skip > else > dmMain.LogLine('Email address skipped'); > > end; > > end > else > begin > > //In case PR_EMAIL_ADDRESS is not found, use PR_DISPLAY_NAME > instead > ADisplayName := > lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-4].Value.lpsza; > try > EMailAddress := > lppRows.aRow[Nrec].lpProps[lppRows.aRow[Nrec].cValues-3].Value.lpsza; > except > dmMain.LogLine('Failed to read PR_EMAIL_ADDRESS, using > PR_DISPLAY_NAME instead'); > EMailAddress := ADisplayName; > end; > > dmMain.LogLine('Recipient #' + IntToStr(Nrec + 1) + ' - email > address: ' + EMailAddress + ' , display name: ' + ADisplayName); > result.AddObject(EMailAddress, > TStringObject.Create(ADisplayName)); > end; > > except > on e: Exception do > dmMain.LogLine('Failed to read email address from recipient table > row with error message: ' + e.Message); > end; > end; > > except > on e: Exception do > dmMain.LogLine('Failed to retrieve recipients table with error > message: ' + e.Message); > end; > > // Free each element in the pRows buffer > FreeProws(lppRows); > > end;
|
|
|