在使用Delphi XE中的Indy发送电子邮件时出现STARTTLS错误

3
我正在尝试使用以下代码从我的应用程序发送电子邮件:

我正在尝试使用以下代码从我的应用程序发送电子邮件:

  Var
  MailMessage : TIdMessage;
  SMTP        : TIdSMTP
   .
   .
   .
 //setup SMTP
 SMTP.Host := 'smtp.gmail.com';
 SMTP.Port := 25;
 //setup mail message
 MailMessage.From.Address := 'fromMe@gmail.com';
 MailMessage.Recipients.EMailAddresses := 'ToSomeOne@hotmail.com';
 MailMessage.Subject := 'Test';
 MailMessage.Body.Text := 'Hello, It is Just for test';

 SMTP.Connect;
 SMTP.Send(MailMessage);

当我运行它时,会生成以下错误。
**ERROR: Must issue a STARTTLS command first. i29sm34080394wbp.22**

我该如何解决这个问题?

你应该熟悉STARTTLS:http://en.wikipedia.org/wiki/STARTTLS和https://www.fastmail.fm/help/technology_ssl_vs_tls_starttls.html都是有帮助的。 - james.garriss
3个回答

9
通过将答案组合在一起,您可以获得以下代码。不要忘记,正如Nathanial Woolls所提到的这里,例如从这里获取libeay32.dllssleay32.dll库,并将其放置在项目文件夹中或以下地方的路径中。
uses
  IdMessage, IdSMTP, IdSSLOpenSSL, IdGlobal, IdExplicitTLSClientServerBase;

procedure SendEmail(const Recipients: string; const Subject: string; const Body: string);
var
  SMTP: TIdSMTP;
  Email: TIdMessage;
  SSLHandler: TIdSSLIOHandlerSocketOpenSSL;
begin
  SMTP := TIdSMTP.Create(nil);
  Email := TIdMessage.Create(nil);
  SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);

  try
    SSLHandler.MaxLineAction := maException;
    SSLHandler.SSLOptions.Method := sslvTLSv1;
    SSLHandler.SSLOptions.Mode := sslmUnassigned;
    SSLHandler.SSLOptions.VerifyMode := [];
    SSLHandler.SSLOptions.VerifyDepth := 0;

    SMTP.IOHandler := SSLHandler;
    SMTP.Host := 'smtp.gmail.com';
    SMTP.Port := 587;
    SMTP.Username := 'yourusername@gmail.com';
    SMTP.Password := 'yourpassword';
    SMTP.UseTLS := utUseExplicitTLS;

    Email.From.Address := 'yourusername@gmail.com';
    Email.Recipients.EmailAddresses := Recipients;
    Email.Subject := Subject;
    Email.Body.Text := Body;

    SMTP.Connect;
    SMTP.Send(Email);
    SMTP.Disconnect;

  finally
    SMTP.Free;
    Email.Free;
    SSLHandler.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SendEmail('recipient@whatever.com', 'Subject', 'Body');
end;

希望这个能有所帮助。

2
摆脱对 SSLHandler.DestinationSSLHandler.HostSSLHandler.Port 属性的赋值。这些属性将由 Connect() 自动填充。 - Remy Lebeau

6
smtp.gmail.com 强制使用 STARTTLS 加密连接。
Indy 9 不支持直接使用 STARTTLS,但 Indy 10 支持。 在连接到服务器之前,在 Indy 10 中,您必须分配一个启用 SSL 的 IOHandler,例如 TIdSSLIOHandlerSocketOpenSSL
参见:http://www.indyproject.org/docsite/html/frames.html?frmname=topic&frmfile=TIdSSLIOHandlerSocketOpenSSL.html 添加以下代码:

var
...
SSLHandler: TIdSSLIOHandlerSocketOpenSSL;

SSLHandler:= TIdSSLIOHandlerSocketOpenSSL.Create(Form1);
SMTP.IOHandler:= SSLHandler;
SMTP.UseTLS:= utUseExplicitTLS;
SMTP.Username:= 'username';
SMTP.Password:= 'password';
SMTP.Port:= 587; 

如果您只是使用非加密的SMTP处理程序(您的ISP的SMTP)发送邮件,则不会遇到此问题。


2
@Johna:说_Indy 9不支持这个_是错误的。 Indy 9支持SSL加密,只是不支持GMail的SMTP服务器需要的STARTTLS命令。 但你可以手动发送STARTTLS命令,只需添加几行额外的代码即可。 关于OnGetPassword事件,仅适用于使用受密码保护的SSL证书的情况(这不是GMail的情况)。 - Remy Lebeau
@RemyLebeau-TeamB,感谢您指出这一点,我已经有一段时间没有使用Indy了。 - Johan
@RemyLebeau,在Indy 8中手动发送STARTTLS是否可行?我有一个使用Indy 8的应用程序。我可以使用SSL连接发送电子邮件,但仅当服务器使用隐式TLS时才能发送。我想添加对STARTTLS的支持。如果可能,请告诉我如何操作。 - CITBL

3
这个错误是因为 Gmail 使用 SSL 和 TLS。您需要使用 Indy 的 SSL IO 处理程序以及适用于您的 Indy 版本的正确 OpenSSL DLL。这里有一个关于如何使其正常工作的教程here

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