使用Delphi从Outlook 2010最简单的撰写电子邮件方式是什么?

3
一些应用程序在不同的电子邮件集成方式下运行良好,包括使用mailto:simulated "发送到...", 以及 Windows 2000 和 2003 环境中的 SMTP。现在这些应用程序将迁移到一个新的 Windows 2008 系统,并使用 Exchange 2010 和 Outlook 2010 客户端。 我们有一个使用案例,其中应用程序创建一个新邮件,设置收件人和主题,添加一个或多个附件,然后在默认邮件客户端中打开它,以便用户在发送之前进行编辑。 您知道在新环境中可行的解决方案吗?我们应该使用第三方库吗?还是已知使用Outlook.Application的OLE自动化代码可用?

你不想让你的应用在使用SMTP发送消息之前由用户处理编辑的原因是什么?除非你需要Outlook在编辑邮件时提供的所有花哨功能,否则这可能是一个更简单的解决方案。 - Marjan Venema
需要Outlook邮件客户端的编辑功能,例如从通讯录中添加电子邮件地址。我们目前尚未使用LDAP / AD集成。 - mjn
5个回答

7
我们使用Jedi JCL库中的jclMapi单元中的JclSimpleBringUpSendMailDialog。
我曾经有一个应用程序,我们内置了一个用户选项,让他们指定是使用SMTP还是MAPI以及各种邮件服务器设置,但Jedi库调用使生活变得更加容易。如果最终用户已经费尽心思在MAPI客户端中设置好所有设置,那么为什么要在我的/我们的软件中再次设置它们呢。
mailto://的问题在于它通常不够可配置,或者邮件客户端没有以相同/标准方式处理参数-然后用户认为您的软件很糟糕,而不是认为他们有一个有问题的邮件客户端。
所以我们只使用MAPI接口。简单易行。

1
这看起来很不错,这将是我最喜欢的解决方案。谢谢! +1 - mjn
我尝试使用当前的JCL版本,并出现了上述描述的错误。 - mjn
嗯。不知道。在普通客户端场景下运行良好,远程桌面上的win 2003服务器也似乎没问题。没有人报告说它无法工作,但我怀疑它并没有被广泛使用。你发布的错误报告提到了dhcpsvc.dll - 也许存在某种名称解析问题。另外,我的代码将jcl调用包装在try...except中,但什么都没有做(!),并注释说JCL通常会弹出自己的错误对话框。因此,异常似乎应该处理得很好。也许是TS上的权限问题。 - shunty
此外...您需要在服务器上安装MAPI组件吗?我知道Win 7默认情况下不会安装很多电子邮件相关的东西 - 您必须从“必备”包中添加一些内容 - 或许这也是服务器上的情况?还有...自从什么时候发布了Windows 2010? - shunty
MAPI已安装,我们有两个终端服务器,有时可以成功打开Outlook客户端,GUI运行正常 - 下一个尝试则会出现冻结的应用程序和上述错误。看起来像是网络驱动程序(dhcp)问题。相同的JCL代码,在Windows 7 / 64位操作系统上,可以无错误地工作。 - mjn

1

我使用这个单元 - 很久以前就归功于Brian Long...

unit UArtMAPI;


interface



procedure ArtMAPISendMail(
            const Subject, MessageText, MailFromName, MailFromAddress,
                  MailToName, MailToAddress: String;
            const AttachmentFileNames: array of String);


implementation



uses
  SysUtils,
  Windows,
  UArtLibrary,
  Dialogs,
  Forms,
  MAPI;

procedure ArtMAPISendMail(
            const Subject, MessageText, MailFromName, MailFromAddress,
                  MailToName, MailToAddress: String;
            const AttachmentFileNames: array of String);
//Originally by Brian Long: The Delphi Magazine issue 60 - Delphi And Email
var
  MAPIError: DWord;
  MapiMessage: TMapiMessage;
  Originator, Recipient: TMapiRecipDesc;
  Files, FilesTmp: PMapiFileDesc;
  FilesCount: Integer;
begin
   FillChar(MapiMessage, Sizeof(TMapiMessage), 0);

   MapiMessage.lpszSubject := PAnsiChar(AnsiString(Subject));
   MapiMessage.lpszNoteText := PAnsiChar(AnsiString(MessageText));

   FillChar(Originator, Sizeof(TMapiRecipDesc), 0);

   Originator.lpszName := PAnsiChar(AnsiString(MailFromName));
   Originator.lpszAddress := PAnsiChar(AnsiString(MailFromAddress));
//   MapiMessage.lpOriginator := @Originator;
   MapiMessage.lpOriginator := nil;


   MapiMessage.nRecipCount := 1;
   FillChar(Recipient, Sizeof(TMapiRecipDesc), 0);
   Recipient.ulRecipClass := MAPI_TO;
   Recipient.lpszName := PAnsiChar(AnsiString(MailToName));
   Recipient.lpszAddress := PAnsiChar(AnsiString(MailToAddress));
   MapiMessage.lpRecips := @Recipient;

   MapiMessage.nFileCount := High(AttachmentFileNames) - Low(AttachmentFileNames) + 1;
   Files := AllocMem(SizeOf(TMapiFileDesc) * MapiMessage.nFileCount);
   MapiMessage.lpFiles := Files;
   FilesTmp := Files;
   for FilesCount := Low(AttachmentFileNames) to High(AttachmentFileNames) do
   begin
     FilesTmp.nPosition := $FFFFFFFF;
     FilesTmp.lpszPathName := PAnsiChar(AnsiString(AttachmentFileNames[FilesCount]));
     Inc(FilesTmp)
   end;

   try
     MAPIError := MapiSendMail(
       0,
       Application.MainForm.Handle,
       MapiMessage,
       MAPI_LOGON_UI {or MAPI_NEW_SESSION},
       0);
   finally
     FreeMem(Files)
   end;

   case MAPIError of
     MAPI_E_AMBIGUOUS_RECIPIENT:
      Showmessage('A recipient matched more than one of the recipient descriptor structures and MAPI_DIALOG was not set. No message was sent.');
     MAPI_E_ATTACHMENT_NOT_FOUND:
      Showmessage('The specified attachment was not found; no message was sent.');
     MAPI_E_ATTACHMENT_OPEN_FAILURE:
      Showmessage('The specified attachment could not be opened; no message was sent.');
     MAPI_E_BAD_RECIPTYPE:
      Showmessage('The type of a recipient was not MAPI_TO, MAPI_CC, or MAPI_BCC. No message was sent.');
     MAPI_E_FAILURE:
      Showmessage('One or more unspecified errors occurred; no message was sent.');
     MAPI_E_INSUFFICIENT_MEMORY:
      Showmessage('There was insufficient memory to proceed. No message was sent.');
     MAPI_E_LOGIN_FAILURE:
      Showmessage('There was no default logon, and the user failed to log on successfully when the logon dialog box was displayed. No message was sent.');
     MAPI_E_TEXT_TOO_LARGE:
      Showmessage('The text in the message was too large to sent; the message was not sent.');
     MAPI_E_TOO_MANY_FILES:
      Showmessage('There were too many file attachments; no message was sent.');
     MAPI_E_TOO_MANY_RECIPIENTS:
      Showmessage('There were too many recipients; no message was sent.');
     MAPI_E_UNKNOWN_RECIPIENT:
       Showmessage('A recipient did not appear in the address list; no message was sent.');
     MAPI_E_USER_ABORT:
       Showmessage('The user canceled the process; no message was sent.');
     SUCCESS_SUCCESS:
       Showmessage('MAPISendMail successfully sent the message.');
   else
     Showmessage('MAPISendMail failed with an unknown error code.');
   end;
end;




end.

我从代码中看不出它是仅发送还是在Outlook中显示草稿邮件?还有UArtLibrary单元是用来做什么的? - mjn

0

我找到了这个例子。它是来自2002年的,所以使用的是更旧版本的Outlook,但是思想应该是一样的。它被用在一个应用程序中,用于向新注册用户发送他们的用户名和密码(别提了,这只是一种限制访问网站的方式,没有敏感信息)。消息被保存在发件箱中,但是如果你仔细查看OleServer和Outlook8(现在可能数字会更高),你应该能找到打开邮件以引起用户注意的方法,而不是直接保存到发件箱。

整个Outlook对象模型可以在msdn上找到:http://msdn.microsoft.com/en-us/library/aa221870%28v=office.11%29.aspx

另一个关于Office自动化的好资源是Deborah Pate的页面:http://www.djpate.freeserve.co.uk/Automation.htm

function TStapWerkt_data.GenerateMailsOutlook(SendDBF: boolean): boolean;
var
  Outlook: TOutlookApplication;
  olNameSpace: NameSpace;
  MailIt: TMailItem;
  AttachedFile: OleVariant;
  i: integer;
  emailaddress: string;
begin
  Result := true;
  Outlook := TOutlookApplication.Create( nil );
  try
    Outlook.ConnectKind := ckNewInstance;
    try
      Outlook.Connect;
      try
        olNameSpace := Outlook.GetNamespace('MAPI');
        olNameSpace.Logon('', '', False, False);
        try

          if SendDBF then begin
            MailIt := TMailItem.Create( nil );
            MailIt.ConnectTo( Outlook.CreateItem( olMailItem ) as MailItem );
            try
              MailIt.Recipients.Add( 'info@bjmsoftware.com' );
              MailIt.Subject := 'StapWerk.dbf';
              MailIt.Body := 'Stap'#13#10;
              AttachedFile := IncludeTrailingBackslash( ExtractFilePath(
                  Stap_db.Stap_Database.DatabaseName ) ) + 'stapwerk.dbf';
              MailIt.Attachments.Add( AttachedFile, EmptyParam, EmptyParam, EmptyParam );
              MailIt.Save;
            finally
              MailIt.Free;
            end;
          end;

          for i := 0 to FNewUsers.Count - 1 do begin
            MailIt := TMailItem.Create( nil );
            MailIt.ConnectTo( Outlook.CreateItem( olMailItem ) as MailItem );
            try
              emailaddress := TStapper( FNewUsers.Items[i] ).Email;
              if emailaddress = '' then begin
                emailaddress := C_MailUnknownAddress;
              end;
              MailIt.Recipients.Add( emailaddress );
              MailIt.Subject := C_MailSubject;
              MailIt.Body := Format( C_MailBody,
                  [TStapper( FNewUsers.Items[i] ).UserId,
                  TStapper( FNewUsers.Items[i] ).Password] );
              MailIt.Save;
            finally
              MailIt.Free;
            end;
          end;

        finally
          olNameSpace.Logoff;
        end;
      finally
        Outlook.Disconnect;
        // We kunnen ondanks ckNewInstance quit niet gebruiken
        // Outlook lijkt de connectkind te negeren en hoe dan ook te koppelen
        // naar een bestaande instantie. En die gooi je dan dus ook dicht met quit.
//        Outlook.quit;
      end;
    finally
      Outlook.free;
    end;
  except
    on E: Exception do begin
      Result := false;
    end;
  end;
end;

0

我已经有这段代码片段并在安装了Outlook 2010的Windows 7开发系统上尝试过了。它失败了,并显示了一个错误消息,稍后我会在这里发布。无论如何,感谢提供链接,它可能会帮助其他人(我也将在Windows 2003系统上尝试它)。 - mjn
嗯,在这种情况下,只要有一个异常,它就无法发挥作用。 - user532231
从代码中可以看出它发送了消息 - 我们需要一种方法先显示消息编辑器,以便用户可以在发送之前首先修改正文、收件人等。也许 Save 方法是一个解决方法,但用户仍然需要手动打开 Outlook 并导航到草稿文件夹。 - mjn
1
@mjn - 在发送之前调用邮件项的“Display”方法来显示消息,而不是调用“Send”方法。 - Sertac Akyuz

0
也许这是打开电子邮件窗口最简单的方式。
System("mailto:someone@example.com?Subject=Hello%20again&body=your%20textBody%20here")

这并不符合问题所要求的文件附件:“*”,需要添加一个或多个附件...” - mjn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接