I wrote some code to read emails from Outlook Inbox and collect attachments.
This is working just fine. I am using Outlook 2019/Office 365.
I can use both Mail.SenderEmailAddress
or Mail.Sender.Address
to get the email address of the sender.
When deploying my application to another computer with Outlook 2016, I get this error:
EOleError: Method 'Sender' not supported by automation object
Same for Mail.SenderEmailAddress
Outlook 2016 or 2019 have the same code stream. See Outlook versions, build numbers and other trivia.
Could you help understanding why I get such error on my client's computer and how can I fix that problem?
Are you aware of a free/commercial library or components that could do that smoothly?
This is somehow linked with my other question about Sending Outlook Email with Delphi.
try
Outlook:=GetActiveOleObject('Outlook.Application') ;
except
Outlook:=CreateOleObject('Outlook.Application') ;
end;
try
oNameSpace := Outlook.GetNamespace('MAPI');
oNameSpace.Logon;
Inbox:= oNameSpace.GetDefaultFolder(6);
iNbMail:= Inbox.Items.Count;
for i:= iNbMail downto 1 do
begin
if VarIsNull(Inbox.Items[i]) or VarIsEmpty(Inbox.Items[i]) then
Continue;
Mail:= Inbox.Items[i];
EmailAddress:= Mail.Sender.Address;
// EmailAddress:= Mail.SenderEmailAddress;
UnReadFlag:= Mail.UnRead;
iNbAttach := Mail.Attachments.Count;
for j := iNbAttach downto 1 do
begin
Attachment:= Mail.Attachments[j];
if ExtractFileExt(Attachment.FileName) = '.pdf' then
begin
SaveName:= TPath.Combine(InboxFolder, Attachment.FileName);
Attachment.SaveAsFile(SaveName);
end;
end;
Mail.UnRead:= False;
end;
finally
Outlook:= Unassigned;
oNameSpace:= Unassigned;
Inbox:= Unassigned;
Mail:= Unassigned;
end;
Inbox folder in Outlook is not restricted to contain only mail messages. When iterating through its items you can encounter various item classes like MailItem
, PostItem
, MeetingItem
, TaskRequestItem
and many others. All of these items support different sets of properties and not all of them have Sender
, SenderEmailAddress
or Attachments
property. If you're interested only in mail items then you need to check item's Class
property:
const
olMail = $0000002B;
{ ... }
for i := iNbMail downto 1 do
begin
Mail := Inbox.Items[i];
if Mail.Class <> olMail then
Continue;
{ here we can assume we're working with MailItem instance }
end;
I doubt that Outlook ever returns null or empty item, so the check you do in your code is pointless. If you're interested in other item classes then check out OlObjectClass
enumeration.
I'm not sure why you prefer to use late-binding, because Delphi already comes with imported type library Outlook2010.pas
to automate Outlook in strongly typed manner. The library is located in OCX\Servers
subfolder of installation folder. In case you need to support pre-2010 Outlook versions you can use unit OutlookXP
or even Outlook2000
instead. The code fore iterating mail items using the type library could look like this:
uses
System.SysUtils, System.Variants, Winapi.ActiveX, Outlook2010;
function GetOutlookApplication: OutlookApplication;
var
ActiveObject: IUnknown;
begin
if Succeeded(GetActiveObject(OutlookApplication, nil, ActiveObject)) then
Result := ActiveObject as OutlookApplication
else
Result := CoOutlookApplication.Create;
end;
procedure ProcessInboxItems;
var
Outlook: OutlookApplication;
Inbox: Folder;
Index: Integer;
LItems: Items;
LMailItem: MailItem;
begin
Outlook := GetOutlookApplication;
Outlook.Session.Logon(EmptyParam, EmptyParam, EmptyParam, EmptyParam);
Inbox := Outlook.Session.GetDefaultFolder(olFolderInbox);
LItems := Inbox.Items;
for Index := LItems.Count downto 1 do
begin
if Supports(LItems.Item(Index), MailItem, LMailItem) then
begin
{ do whatever you wish with LMailItem }
end;
end;
end;