Coletando e-mails da caixa de entrada do Outlook com Delphi

Oct 29 2020

Eu escrevi alguns códigos para ler e-mails da caixa de entrada do Outlook e coletar anexos.

Isso está funcionando muito bem. Estou usando o Outlook 2019 / Office 365.

Posso usar os dois Mail.SenderEmailAddressou Mail.Sender.Addresspara obter o endereço de e-mail do remetente.

Ao implantar meu aplicativo em outro computador com Outlook 2016, recebo este erro:

EOleError: Método 'Sender' não suportado pelo objeto de automação

Mesmo para Mail.SenderEmailAddress

Outlook 2016 ou 2019 têm o mesmo fluxo de código. Veja as versões do Outlook, números de compilação e outras curiosidades .

Você poderia ajudar a entender por que recebo esse erro no computador do meu cliente e como posso corrigir esse problema?

Você está ciente de uma biblioteca gratuita / comercial ou componentes que podem fazer isso sem problemas?

Isso está de alguma forma relacionado com a minha outra pergunta sobre como enviar e-mail do Outlook com 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;

Respostas

2 PeterWolf Oct 30 2020 at 06:43

A pasta da caixa de entrada no Outlook não se restringe a conter apenas mensagens de correio. Quando a iteração através de seus itens que você pode encontrar várias classes de itens como MailItem, PostItem, MeetingItem, TaskRequestIteme muitos outros. Todos esses itens oferecem suporte a diferentes conjuntos de propriedades e nem todos têm Sender, SenderEmailAddressou Attachmentspropriedade. Se você estiver interessado apenas em itens de correio, será necessário verificar as Classpropriedades do item :

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;

Duvido que o Outlook retorne um item nulo ou vazio, então a verificação que você faz em seu código é inútil. Se você estiver interessado em outras classes de itens, verifique a OlObjectClassenumeração.

Não sei por que você prefere usar a ligação tardia , porque o Delphi já vem com uma biblioteca de tipos importada Outlook2010.paspara automatizar o Outlook de maneira fortemente tipada. A biblioteca está localizada na OCX\Serverssubpasta da pasta de instalação. Caso seja necessário oferecer suporte a versões pré-2010 do Outlook, você pode usar a unidade OutlookXPou até mesmo em seu Outlook2000lugar. O código antes de iterar itens de email usando a biblioteca de tipos poderia ser assim:

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;