2015/03/10

Delphi XE7使用Indy 10.6.1連結Gmail SMTP


緣起

我在KTOP中回答「xe6 使用gmail的問題」這個主題,因為程式碼編排有問題,故在這裡另外轉貼。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
unit Unit1;
 
interface
 
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdExplicitTLSClientServerBase, IdSMTP, IdSSLOpenSSL,
  IdMessage, IdAttachmentFile, Vcl.StdCtrls;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
/// <summary>
/// Sends an email using the specified SMTP server.
/// </summary>
/// <param name="sendTo">The email address of the recipient.</param>
/// <param name="subject">The subject of the email.</param>
/// <param name="body">The body of the email.</param>
/// <param name="attachFiles">A TStringList containing file paths to be attached to the email. Can be nil if no attachments are required.</param>
/// <param name="smtpHost">The hostname or IP address of the SMTP server.</param>
/// <param name="smtpPort">The port number of the SMTP server.</param>
/// <param name="smtpUser">The username to authenticate with the SMTP server.</param>
/// <param name="smtpPass">The password to authenticate with the SMTP server.</param>
/// <param name="tls">The type of TLS encryption to use. Can be utNoTLSSupport if TLS is not supported by the SMTP server.</param>
/// <returns>True if the email was sent successfully, false otherwise.</returns>    
    function SendEmail(sendTo: string;
                    subject: string;
                    body: string;
                    attachFiles: TStringList;
                    smtpHost: string;
                    smtpPort: Integer;
                    smtpUser: string;
                    smtpPass: string;
                    tls: TIdUseTLS): boolean;
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  SendEmail( 'mybuddy@example.com', // 目的地E-Mail
                    'This is the subject',
                    'This is the body of the email....',
                    nil,
                    'smtp.gmail.com',
                    587,
                    'myusername@gmail.com', // 登入帳號
                    'mypassword'{ 登入密碼 }, utUseExplicitTLS);
end;
 
function TForm1.SendEmail(sendTo, subject, body: string;
  attachFiles: TStringList; smtpHost: string; smtpPort: Integer; smtpUser,
  smtpPass: string; tls: TIdUseTLS): boolean;
var
    smtp: TIdSmtp;
    ssl: TIdSSLIOHandlerSocketOpenSSL;
    msg: TIdMessage;
    i: Integer;
begin
    smtp:=TIdSmtp.Create(nil);
    ssl:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
    msg:=TIdMessage.Create(nil);
    try
 
        try
            smtp.Host:=smtpHost;
            smtp.Port:=smtpPort;
            smtp.Username:=smtpUser;
            smtp.Password:=smtpPass;
 
            //smtp.OnConnected :=IdSMTP1Connected;
            //smtp.OnDisconnected :=IdSMTP1Disconnected;
            //smtp.OnFailedRecipient :=IdSMTP1FailedRecipient;
            //smtp.OnStatus :=IdSMTP1Status;
            //smtp.OnTLSNotAvailable :=IdSMTP1TLSNotAvailable;
            //smtp.OnWork :=IdSMTP1Work;
 
            if not (tls=utNoTLSSupport) then begin
                ssl.Destination:=smtpHost + ':' + IntToStr(smtpPort);
                ssl.Host:=smtpHost;
                ssl.Port:=smtpPort;
                ssl.SSLOptions.Method:=sslvTLSv1;
 
                //ssl.OnStatusInfo:=IdSSLIOHandlerSocketOpenSSL1StatusInfo;
                //ssl.OnGetPassword:=IdSSLIOHandlerSocketOpenSSL1GetPassword;
                //ssl.OnStatus:=IdSSLIOHandlerSocketOpenSSL1Status;
 
                smtp.IOHandler:=ssl;
                smtp.UseTLS:=tls;
            end;
 
            msg.Recipients.EMailAddresses := sendTo;
            msg.Subject:=subject;
            msg.Body.Text:=body;
 
            if(Assigned(attachFiles)) then begin
                for i := 0 to attachFiles.Count - 1 do begin
                   if FileExists(attachFiles[i]) then
                        TIdAttachmentFile.Create(msg.MessageParts, attachFiles[i]);
                end;
            end;
 
            smtp.Connect;
            smtp.Send(msg);
            smtp.Disconnect;
 
            result:=true;
        finally
            msg.Free;
            ssl.Free;
            smtp.Free;
        end;
    except
       result:=false;
    end;
end;
 
end.

結論:

使用 Indy 10.6.1 連接 Gmail SMTP 並成功發送和接收電子郵件。它在 Delphi XE7 中運作正常,可以作為開發人員實現電子郵件發送功能的參考。

 和你分享。😉

參考資料來源:

12 則留言:

  1. 請教..
    我的環境為 win7 + xe7
    使用上述程式, 執行時出現錯誤訊息如下:
    ...EIdSMTPReplyError wiht message....
    Please log in via your web browser and then try again.
    Learn more at
    https://support.google.com/mail/bin/answer.py?answer=78754

    sorry .. 無法貼圖
    有試著到 https://support.google.com/mail/bin/answer.py?answer=78754 依其相關操作建議
    但並無法解決目前問題
    不知前輩有何建議, 謝謝

    回覆刪除
  2. 我在測試時
    「有發生不能寄出」的成因是「Could not load SSL library」

    請試一下這篇:Indy 操作 SMTP 發生 "Could not load SSL library"?
    http://grandruru.blogspot.tw/2014/12/indy-smtp-could-not-load-ssl-library.html

    升級 SSL 後再試試看。
    以上

    回覆刪除
  3. smtp.connect; 這行還是正常的
    smtp.send(msg); 這行最後的結果如上
    下面列出執行時的相關訊息如下:
    IdSSLIOHandlerSocketOpenSSL1Status AStatusText:=Resolving hostname smtp.gmail.com.
    IdSSLIOHandlerSocketOpenSSL1Status AStatusText:=Connecting to 74.125.203.108.
    IdSMTP1Status AStatusText:=Connected.
    IdSMTP1Connected
    Start Send Message ----------------------------
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "before/connect initialization"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "before/connect initialization"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 write client hello A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 read server hello A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 read server certificate A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 read server key exchange A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 read server done A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 write client key exchange A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 write change cipher spec A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 write finished A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 flush data"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 read server session ticket A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSLv3 read finished A"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSL negotiation finished successfully"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=SSL status: "SSL negotiation finished successfully"
    IdSSLIOHandlerSocketOpenSSL1StatusInfo AMsg:=Cipher: name = ECDHE-RSA-RC4-SHA; description = ECDHE-RSA-RC4-SHA SSLv3 Kx=ECDH Au=RSA Enc=RC4(128) Mac=SHA1
    ; bits = 128; version = TLSv1/SSLv3;

    回覆刪除
  4. 看不出錯誤在哪邊
    你的帳號資料有輸入正確嗎?

    回覆刪除
  5. 謝謝您的回覆, 下載並安裝了..但顯然不是這個問題
    再研究研究看看好了, 3Q

    回覆刪除
  6. 請問一下,可以一次寄多人嗎??
    3Q

    回覆刪除
    回覆
    1. 寄多人不是問題,使用 for 迴圈或是副本方式,都能夠滿足你的要求 😉

      刪除
    2. 感謝回覆,
      不好意思,我的問題沒說清楚,
      我說的多人,是指同一封信,收件者有2個以上,

      msg.Recipients.EMailAddresses:=sendTo;
      一次只有一人,要改多人如何改???
      3Q

      刪除
    3. 使用分號區隔收件人,例如:abc@mail.com;cde@mail.com

      就可以達成一封信傳給多人。😉

      刪除
    4. 測試成功,
      感謝回覆

      刪除
  7. 有些mail server要作驗證
    設定如下圖
    https://webmail.ntnu.edu.tw/wmail/faq/Outlook.files/image005.jpg
    請問,要如何修改?
    3Q

    回覆刪除