Delphi XE5发送电子邮件

3

我试图使用Indy组件从Delphi XE5 (Android)发送电子邮件:

在表单中,我有一个TIdSMTP和一个TIDMessage

当表单被创建时:

testform:=Ttestform.create(self);
testform.show;

应用程序停止运行,我不知道出了什么问题... 我猜测Indy组件在Android上不兼容...

  IdSMTP1.Heloname:='test';
  IdSMTP1.Host:='smtp.gmail.com';
  IdSMTP1.Username:='umail@gmail.com';
  IdSMTP1.Port:=465;
  IdSMTP1.Password:='pass';

  if IdSMTP1.Connected=True then IdSMTP1.Disconnect;

  IdMessage1.clear;
  IdMessage1.From.Text :='Testing';
  IdMessage1.BccList.EMailAddresses :='umail@gmail.com';
  IdMessage1.Priority := mpHigh;
  IdMessage1.Sender.Text:='Umail';
  IdMessage1.Subject := 'Subject';
  IdMessage1.Body.Add('test');
  IdSMTP1.Connect;
  Try
    IdSMTP1.Send(IdMessage1);
  except
  End;

有人使用这个吗?!

表单不显示,应用已停止... 请在此处查看完整源代码http://pastebin.com/iGtJrHHs


你在 IdMessage1.BccList.EMailAddresses :='umail@gmail.com;; 行末缺少引号。 - Marcus Adams
虽然我无法让 IdSMTP 做任何事情,除了在我点击“发送邮件”按钮时使我的应用程序无响应(第一代 Nexus 7)。表单在应用程序启动时显示得很好。也许您可以从一个空白应用程序开始,逐个添加组件并重新开始。 - Anthony Eischens
然后你需要调试你的应用程序。首先确认TIdSMTP是否真的有问题,不要仅仅假设它有问题。如果它有问题(我怀疑),你可以跟踪其源代码以找到实际的挂起点。或者,你可以简单地重新设计你的代码,将TIdSMTP从TForm中移除,并将其移到一个工作线程中(这样做是正确的,因为你永远不应该阻塞主线程)。 - Remy Lebeau
5个回答

4

虽然这不是直接解决Indy的问题,但如果您考虑改用Android内置的电子邮件创建选项,您可以使用类似以下代码的代码:

uses
  FMX.Helpers.Android,
  Androidapi.JNIBridge,
  Androidapi.JNI.JavaTypes,
  Androidapi.JNI.GraphicsContentViewText;
...
procedure CreateEmail(const Recipient, Subject, Content: string);
var
  Intent: JIntent;
  Recipients: TJavaObjectArray<JString>;
begin
  Intent := TJIntent.JavaClass.init(TJIntent.JavaClass.ACTION_SEND);
  Recipients := TJavaObjectArray<JString>.Create(1);
  Recipients.Items[0] := StringToJString(Recipient);
  Intent.putExtra(TJIntent.JavaClass.EXTRA_EMAIL, Recipients);
  Intent.putExtra(TJIntent.JavaClass.EXTRA_SUBJECT, StringToJString(Subject));
  Intent.putExtra(TJIntent.JavaClass.EXTRA_TEXT, StringToJString(Content));
  Intent.setType(StringToJString('plain/text'));
  SharedActivity.startActivity(TJIntent.JavaClass.createChooser(Intent,
    StrToJCharSequence('Which email app?')));
end;

我会让其他人提供Indy问题的解决方案。

我接受这个解决方案来解决问题,因为Indy IdSMTP不兼容Android。 - quimdotractor
1
是的,TIdSMTP与Android兼容。其他人已经成功使用它。您是我见过第一个报告使用它出现问题的人。 - Remy Lebeau
我有同样的问题。@Remy,也许你可以发布你的解决方案?我在代码中创建TIdMessage,当我更改它的属性时,应用程序会挂起(无法响应任何点击)。目前我将采用blong的解决方案。 - mad
@mad:仅仅设置属性值不可能导致程序挂起。一定是其他问题导致的。请问哪一行代码导致了程序挂起? - Remy Lebeau

1

Indy兼容Android。这不是Android的问题,而是配置问题。

Gmail的465端口使用隐式SSL加密连接。连接到465端口后,服务器希望您的应用程序发起SSL握手以建立SSL会话,然后才能交换任何SMTP数据。

在连接之前,您必须将TIdSSLIOHandlerOpenSSL组件附加到TIdSMTP.IOHandler属性上,然后将TIdSMTP.UseTLS属性设置为utUseImplicitTLS。如果没有这样做,TIdSMTP将不会发送SSL握手。它只会等待服务器的SMTP问候语,直到首先建立SSL会话。因此会发生死锁,除非您将TIdSMTP.ReadTimeout属性设置为非无限值,以便TIdSMTP.Connect()在未收到SMTP问候语时引发异常。


我改成了25号端口,但问题仍然存在...表格没有显示。 - quimdotractor
连接到25端口时,客户端必须在连接并检索SMTP问候语之后发出“STARTTLS”命令,然后再登录。在TIdSMTP中,可以通过将其“UseTLS”属性设置为“utUseExplicitTLS”来完成。 - Remy Lebeau

1

用户1147833;

连接到服务器后,您应该进行身份验证操作。

只需切换到您的代码;

IdSMTP1.Connect;
IdSMTP1.Authenticate;
  Try
    IdSMTP1.Send(IdMessage1);
  except
  End;

我正在使用Indy发送大量电子邮件,如果您愿意,我可以分享详细的代码。但是它是为我的进程开发的,不兼容Android。但似乎您的应用程序已停止,因为它未经过身份验证,无法继续进行。 我认为您代码中的错误很简单,只需在代码中添加一行即可。请随时将“错误代码”发送到这里,以便我们了解情况。 - ikutluay
不起作用,谢谢。表单在显示之前停止...所以不是身份验证失败,而是IdSMTP中的问题(我认为)。 - quimdotractor
TIdSMTP.Send() 方法会在内部调用 TIdSMTP.Authenticate(),因此无需显式调用它。 - Remy Lebeau
我做不到,因为表格没有显示...我认为是一个组件“构造器”,因为当我调用formsender:=Tformsender.create(self); formsender.show;应用程序不响应。只是停止了。 - quimdotractor
除非您在表单的 OnShow 事件中执行阻塞套接字操作,否则 TIdSMTP(或任何其他Indy组件)中没有任何东西应该防止表单显示。 - Remy Lebeau
显示剩余2条评论

1
清理了一些项目,如果您的表单未实际显示,则这些项目都无法帮助。
以下代码成功地从第一代Nexus 7发送了一条消息,使用需要身份验证并在25号端口上运行的SMTP服务器。
如果您真的连接到Google服务器的465端口,则必须使用加密,而此代码不涉及加密。
简单的IdMessage1.From.Text := 'blah blah'; 赋值未能正常工作,因此您将看到我替换了IdMessage1.From.Address和其他IdMessage1属性的类似属性。
unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdExplicitTLSClientServerBase, IdMessageClient, IdSMTPBase, IdSMTP, IdMessage,
  FMX.StdCtrls, FMX.Edit;

type
  Ttestform = class(TForm)
    IdSMTP1: TIdSMTP;
    IdMessage1: TIdMessage;
    btnMessageSend: TButton;
    edtUsername: TEdit;
    edtPassword: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    edtFrom: TEdit;
    Label3: TLabel;
    edtTo: TEdit;
    Label4: TLabel;
    edtServer: TEdit;
    Label5: TLabel;
    edtPort: TEdit;
    Label6: TLabel;
    procedure btnMessageSendClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  testform: Ttestform;

implementation

{$R *.fmx}

procedure Ttestform.btnMessageSendClick(Sender: TObject);
var
  intPort: Integer;
begin
  ShowMessage('In button click');
  IdSMTP1.Heloname:='test';
  IdSMTP1.Host:=edtServer.Text;
  IdSMTP1.Username:=edtUsername.Text;
  intPort := 25;
  ShowMessage('Before strtoint');
  TryStrToInt(edtPort.Text, intPort);
  ShowMessage('After strtoint');
  IdSMTP1.Port:= intPort;
  IdSMTP1.Password:=edtPassword.Text;

  if IdSMTP1.Connected=True then IdSMTP1.Disconnect;
  IdMessage1.Clear;
  IdMessage1.From.Address := edtFrom.Text;
  IdMessage1.Recipients.Add;
  IdMessage1.Recipients.Items[0].Address := edtTo.Text;
  IdMessage1.Priority := mpHigh;
  IdMessage1.Sender.Address:=edtFrom.Text;
  IdMessage1.Subject := 'Subject';
  IdMessage1.Body.Add('test');
  IdSMTP1.Connect;
  IdSMTP1.Send(IdMessage1);
end;

end.

请查看完整源代码的链接...表单不显示,我无法点击“连接”按钮。 - quimdotractor

0

在将应用程序部署到 Android 设备之前,请在 Win32 平台上运行并检查是否正常。 请确保 OpenSSL DLL(libeay32.dll 和 ssleay32.dll)放置在同一个目录下,但这对于 Android 不适用。 以下是我的代码。

procedure TForm1.Button1Click(Sender: TObject);
begin
with IdMessage1 do
begin
  Recipients.EMailAddresses := 'test@gmail.com';
  From.Address              := 'test@gmail.com';
  From.Name                 := 'Self';
  CCList.EMailAddresses     := '';
  BccList.EMailAddresses    := '';
  Priority                  := mpNormal;
  Subject                   := 'Test Mail Subject';
  Body.Add('Test Mail Body');
end;

with IdSMTP1 do
begin
  Host      := 'smtp.gmail.com';
  Username  := 'xxxxxxx';
  Password  := 'yyyyyyy';
  IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(Self);
  Port      := 465;
  UseTLS    := utUseImplicitTLS;

  try
  Connect;
  except
  end;

  if not Connected then
  begin
    Showmessage('Error');
    Exit;
  end;

  try
  Send(IdMessage1);
  finally
  Disconnect;
  end;

 end;
end;

谢谢你的代码,但是这个代码在我的电脑上运行良好,但是在其他机器上会出现错误...为什么会这样? - Armin Taghavizad

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