{"id":3549,"date":"2016-02-24T17:29:27","date_gmt":"2016-02-24T09:29:27","guid":{"rendered":"http:\/\/blog.qdac.cc\/?p=3549"},"modified":"2019-11-18T17:39:04","modified_gmt":"2019-11-18T09:39:04","slug":"%e6%9d%82%e8%b0%88-%e5%9f%ba%e4%ba%8e-tidsmtp-%e7%9a%84%e9%82%ae%e4%bb%b6%e5%8f%91%e9%80%81%e4%bb%a3%e7%a0%81","status":"publish","type":"post","link":"https:\/\/blog.qdac.cc\/?p=3549","title":{"rendered":"[\u6742\u8c08] \u57fa\u4e8e TIdSMTP \u7684\u90ae\u4ef6\u53d1\u9001\u4ee3\u7801"},"content":{"rendered":"<h4><strong>\u3010\u66f4\u65b0\u65e5\u5fd7\u3011<\/strong><\/h4>\n<p>2019.11.18<\/p>\n<ul>\n<li>\u6ce8\u610f\u4f7f\u7528 QQ \u90ae\u7bb1\u53d1\u9001\u90ae\u4ef6\u65f6\uff0c\u8981\u4f20\u5b83\u7684\u6388\u6743\u7801\u3002\u5177\u4f53\u53c2\u8003<a href=\"https:\/\/service.mail.qq.com\/cgi-bin\/help?subtype=1&amp;&amp;id=28&amp;&amp;no=1001256\">\u5b98\u65b9\u8bf4\u660e<\/a><\/li>\n<\/ul>\n<p>2016.2.25<\/p>\n<blockquote>\n<ul>\n<li>\u5df2\u77e5 Indy \u5728 android 6.0 \u4e0a\u65e0\u6cd5\u6b63\u786e\u7684\u521d\u59cb\u5316OpenSSL\u5e93\uff0c\u9020\u6210\u65e0\u6cd5\u4f7f\u7528 SendBySSL \u51fd\u6570\uff0c\u901a\u8fc7\u52a0\u5bc6\u901a\u9053\u53d1\u9001\u90ae\u4ef6\uff0c\u4f46 Send \u662fOK\u7684\u3002\u89e3\u51b3\u529e\u6cd5\uff1a<br \/>\n\uff081\uff09\u3001\u7528 Send \u53d1\u9001\u90ae\u4ef6\uff0c\u4e0d\u4f7f\u7528SSL\uff1b<br \/>\n\uff082\uff09\u3001\u7528 Android 5 \u7684 libssl.so \u653e\u5230\u7a0b\u5e8f\u7684\u542f\u52a8\u76ee\u5f55\u4e0b\uff1b<br \/>\n\uff083\uff09\u3001\u7b49\u5f85 Idera \u7684\u5b98\u65b9\u66f4\u65b0\uff0c\u53c2\u8003<a href=\"https:\/\/forums.embarcadero.com\/thread.jspa?threadID=118096\" target=\"_blank\" rel=\"noopener noreferrer\">\u5b98\u65b9\u8bba\u575b<\/a>\u3002<\/li>\n<li>\u4fee\u6b63\u4e86\u5728 Android \u53d1\u9001\u90ae\u4ef6\u65f6\uff0c\u4e2d\u6587\u6807\u9898\u51fa\u73b0\u4e71\u7801\u7684\u95ee\u9898<\/li>\n<\/ul>\n<\/blockquote>\n<h4>\u3010\u6b63\u6587\u3011<\/h4>\n<p>\u8fd9\u4e2a\u662f\u81ea\u5df1\u5199\u7684 SMTP \u00a0\u53d1\u9001\u90ae\u4ef6\u7684\u4ee3\u7801\uff0c\u6e23\u6d6a\u6628\u5929\u4e0d\u884c\u662f\u6e23\u6d6a\u7684\u5c0f\u9738\u738b\u670d\u52a1\u5668\u51fa\u95ee\u9898\u4e86\uff0c\u4eca\u5929\u597d\u4e86\u3002\u73b0\u5728\u6e23\u6d6a\u548cQQ \u90ae\u7bb1\u6d4b\u8bd5\u901a\u8fc7\u3002\u6211\u81ea\u5df1\u53ea\u5728 Delphi 10 \u4e0a\u6d4b\u8bd5\u901a\u8fc7\uff0c\u5176\u5b83\u7684\u73af\u5883\u5c31\u8bf7\u5927\u5bb6\u81ea\u5df1\u6d4b\u8bd5\u4e86\u3002\u672c\u4eba\u4e0d\u627f\u8bfa\u7a0b\u5e8f\u6ca1\u6709 Bug\uff0c\u6709\u95ee\u9898\uff0c\u8bf7\u53ca\u65f6\u544a\u8bc9\u6211\uff0c\u5927\u5bb6\u4e00\u8d77\u6539\u8fdb\u3002<\/p>\n<pre class=\"lang:delphi decode:true \">unit sendmail;\n\ninterface\n\n{$I 'qdac.inc'}\n\n{\n  \u53d1\u9001\u90ae\u4ef6\u5b9e\u73b0\u5355\u5143\uff0c\u65b9\u4fbf\u53d1\u9001\u90ae\u4ef6\uff0c\u60a8\u53ef\u4ee5\u514d\u8d39\u4f7f\u7528\u672c\u5355\u5143\uff0c\u4f46\u8bf7\u4fdd\u7559\u7248\u6743\u4fe1\u606f\n  (C)2016,swish,chinawsb@sina.com\n  \u672c\u5355\u5143\u5b9e\u73b0\u53c2\u8003\u4e86 BCCSafe \u7684\u5b9e\u73b0\uff0c\u8be6\u60c5\u53c2\u8003\uff1a\n  http:\/\/www.bccsafe.com\/delphi%E7%AC%94%E8%AE%B0\/2015\/05\/12\/IndySendMail\/?utm_source=tuicool&utm_medium=referral\n}\nuses classes, sysutils;\n\ntype\n  PMailAttachment = ^TMailAttachment;\n\n  TMailAttachment = record\n    ContentType: UnicodeString;\n    ContentId: UnicodeString;\n    ContentFile: UnicodeString;\n    ContentStream: TStream;\n  end;\n\n  IMailAttachments = interface\n    procedure AddFile(const AFileName: UnicodeString;\n      const AContentId: UnicodeString = '');\n    procedure AddStream(AData: TStream; const AContentType: UnicodeString;\n      const AContentId: UnicodeString = '');\n    function GetCount: Integer;\n    function GetItems(AIndex: Integer): PMailAttachment;\n    property Count: Integer read GetCount;\n    property Items[AIndex: Integer]: PMailAttachment read GetItems;\n  end;\n\n  TMailSender = record\n  public\n    SMTPServer: UnicodeString; \/\/ \u670d\u52a1\u5668\u5730\u5740\n    SMTPPort: Integer; \/\/ \u670d\u52a1\u5668\u7aef\u53e3\n    UserName: UnicodeString; \/\/ \u7528\u6237\u540d\n    Password: UnicodeString; \/\/ \u5bc6\u7801\n    CCList: UnicodeString; \/\/ \u6284\u9001\u5730\u5740\u5217\u8868\n    BCCList: UnicodeString; \/\/ \u6697\u6284\u9001\u5730\u5740\u5217\u8868\n    Attachements: IMailAttachments; \/\/ \u9644\u4ef6\n    SenderName: UnicodeString; \/\/ \u53d1\u9001\u8005\u59d3\u540d\n    SenderMail: UnicodeString; \/\/ \u53d1\u9001\u8005\u90ae\u7bb1\n    RecipientMail: UnicodeString; \/\/ \u6536\u4ef6\u4eba\u90ae\u7bb1\n    Subject: UnicodeString; \/\/ \u90ae\u4ef6\u4e3b\u9898\n    Body: UnicodeString; \/\/ \u90ae\u4ef6\u5185\u5bb9\n    LastError: UnicodeString;\n    UseSASL: Boolean;\n  private\n  public\n    class function Create(AServer, AUserName, APassword: UnicodeString)\n      : TMailSender; overload; static;\n    class function Create: TMailSender; overload; static;\n    function Send: Boolean;\n    function SendBySSL: Boolean;\n  end;\n\n  TGraphicFormat = (gfUnknown, gfBitmap, gfJpeg, gfPng, gfGif, gfMetafile,\n    gfTga, gfPcx, gfTiff, gfIcon, gfCursor, gfIff, gfAni);\nfunction DetectImageFormat(AStream: TStream): TGraphicFormat; overload;\nfunction DetectImageFormat(AFileName: String): TGraphicFormat; overload;\nfunction EncodeMailImage(AStream: TStream; AId: UnicodeString = '';\n  AWidth: UnicodeString = ''; AHeight: UnicodeString = '')\n  : UnicodeString; overload;\nfunction EncodeMailImage(AFileName: UnicodeString; AId: UnicodeString = '';\n  AWidth: UnicodeString = ''; AHeight: UnicodeString = '')\n  : UnicodeString; overload;\n\nvar\n  DefaultSMTPServer: String;\n  DefaultSMTPUserName: String;\n  DefaultSMTPPassword: String;\n\nimplementation\n\nuses\n  IdComponent, IdTCPConnection, IdTCPClient, IdExplicitTLSClientServerBase,\n  IdMessage, IdMessageClient, IdMessageBuilder, IdSMTPBase, IdBaseComponent,\n  IdIOHandler, IdSmtp,\n  IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdSASLLogin,\n  IdSASL_CRAM_SHA1, IdSASL, IdSASLUserPass, IdSASL_CRAMBase, IdSASL_CRAM_MD5,\n  IdSASLSKey, IdSASLPlain, IdSASLOTP, IdSASLExternal, IdSASLDigest,\n  IdSASLAnonymous, IdUserPassProvider, QString, EncdDecd{$IF RTLVersion&gt;27},\n  NetEncoding{$IFEND}{$IFDEF UNICODE}, Generics.Collections{$ENDIF};\n\nresourcestring\n  SUnsupportImageFormat = '\u4e0d\u652f\u6301\u7684\u56fe\u7247\u683c\u5f0f\uff0cHTML\u4e2d\u56fe\u7247\u53ea\u652f\u6301JPG\/PNG\/GIF\/BMP';\n\ntype\n{$IF RTLVersion&gt;=21}\n  TAttachmentList = TList&lt;PMailAttachment&gt;;\n{$ELSE}\n  TAttachmentList = TList;\n{$IFEND}\n\n  TMailAttachments = class(TInterfacedObject, IMailAttachments)\n  protected\n    FItems: TAttachmentList;\n    procedure AddFile(const AFileName: UnicodeString;\n      const AContentId: UnicodeString = '');\n    procedure AddStream(AData: TStream; const AContentType: UnicodeString;\n      const AContentId: UnicodeString = '');\n    function GetCount: Integer;\n    function GetItems(AIndex: Integer): PMailAttachment;\n    procedure DoInitializeISO(var VHeaderEncoding: Char; var VCharSet: string);\n  public\n    constructor Create; overload;\n    destructor Destroy; override;\n  end;\n  { TMailSender }\n\nclass function TMailSender.Create(AServer, AUserName, APassword: UnicodeString)\n  : TMailSender;\nvar\n  AHost: UnicodeString;\nbegin\n  AHost := DecodeTokenW(AServer, ':', #0, true, true);\n  Result.SMTPServer := AHost;\n  if not TryStrToInt(AServer, Result.SMTPPort) then\n    Result.SMTPPort := 25;\n  Result.UserName := AUserName;\n  Result.Password := APassword;\n  Result.Attachements := TMailAttachments.Create;\n  Result.UseSASL := true;\nend;\n\nprocedure BuildHtmlMessage(const AData: TMailSender; AMsg: TIdMessage);\nvar\n  I: Integer;\n  ABuilder: TIdMessageBuilderHtml;\nbegin\n  ABuilder := TIdMessageBuilderHtml.Create;\n  try\n    ABuilder.HtmlCharSet := 'UTF-8';\n    if StartWithW(PWideChar(AData.Body), '&lt;', False) then\n      ABuilder.Html.Text := AData.Body\n    else\n      ABuilder.PlainText.Text := AData.Body;\n    for I := 0 to AData.Attachements.Count - 1 do\n    begin\n      with AData.Attachements.Items[I]^ do\n      begin\n        if Assigned(ContentStream) then\n          ABuilder.Attachments.Add(ContentStream, ContentType, ContentId)\n        else if Length(ContentFile) &gt; 0 then\n          ABuilder.Attachments.Add(ContentFile, ContentId);\n      end;\n    end;\n    ABuilder.FillMessage(AMsg);\n  finally\n    FreeAndNil(ABuilder);\n  end;\n  AMsg.CharSet := 'UTF-8';\n  AMsg.Body.Text := AData.Body;\n  AMsg.Sender.Text := AData.SenderMail;\n  AMsg.From.Address := AData.SenderMail;\n  AMsg.From.Name := AData.SenderName;\n  AMsg.ReplyTo.EMailAddresses := AData.SenderMail;\n  AMsg.Recipients.EMailAddresses := AData.RecipientMail;\n  AMsg.Subject := AData.Subject;\n  AMsg.CCList.EMailAddresses := AData.CCList;\n  AMsg.ReceiptRecipient.Text := '';\n  AMsg.BCCList.EMailAddresses := AData.BCCList;\nend;\n\nprocedure InitSASL(ASmtp: TIdSmtp; AUserName, APassword: String);\nvar\n  IdUserPassProvider: TIdUserPassProvider;\n  IdSASLCRAMMD5: TIdSASLCRAMMD5;\n  IdSASLCRAMSHA1: TIdSASLCRAMSHA1;\n  IdSASLPlain: TIdSASLPlain;\n  IdSASLLogin: TIdSASLLogin;\n  IdSASLSKey: TIdSASLSKey;\n  IdSASLOTP: TIdSASLOTP;\n  IdSASLAnonymous: TIdSASLAnonymous;\n  IdSASLExternal: TIdSASLExternal;\nbegin\n  IdUserPassProvider := TIdUserPassProvider.Create(ASmtp);\n  IdUserPassProvider.UserName := AUserName;\n  IdUserPassProvider.Password := APassword;\n\n  IdSASLCRAMSHA1 := TIdSASLCRAMSHA1.Create(ASmtp);\n  IdSASLCRAMSHA1.UserPassProvider := IdUserPassProvider;\n  IdSASLCRAMMD5 := TIdSASLCRAMMD5.Create(ASmtp);\n  IdSASLCRAMMD5.UserPassProvider := IdUserPassProvider;\n  IdSASLSKey := TIdSASLSKey.Create(ASmtp);\n  IdSASLSKey.UserPassProvider := IdUserPassProvider;\n  IdSASLOTP := TIdSASLOTP.Create(ASmtp);\n  IdSASLOTP.UserPassProvider := IdUserPassProvider;\n  IdSASLAnonymous := TIdSASLAnonymous.Create(ASmtp);\n  IdSASLExternal := TIdSASLExternal.Create(ASmtp);\n  IdSASLLogin := TIdSASLLogin.Create(ASmtp);\n  IdSASLLogin.UserPassProvider := IdUserPassProvider;\n  IdSASLPlain := TIdSASLPlain.Create(ASmtp);\n  IdSASLPlain.UserPassProvider := IdUserPassProvider;\n\n  ASmtp.SASLMechanisms.Add.SASL := IdSASLCRAMSHA1;\n  ASmtp.SASLMechanisms.Add.SASL := IdSASLCRAMMD5;\n  ASmtp.SASLMechanisms.Add.SASL := IdSASLSKey;\n  ASmtp.SASLMechanisms.Add.SASL := IdSASLOTP;\n  ASmtp.SASLMechanisms.Add.SASL := IdSASLAnonymous;\n  ASmtp.SASLMechanisms.Add.SASL := IdSASLExternal;\n  ASmtp.SASLMechanisms.Add.SASL := IdSASLLogin;\n  ASmtp.SASLMechanisms.Add.SASL := IdSASLPlain;\n\nend;\n\nprocedure AddSSLSupport(ASmtp: TIdSmtp);\nvar\n  SSLHandler: TIdSSLIOHandlerSocketOpenSSL;\nbegin\n  SSLHandler := TIdSSLIOHandlerSocketOpenSSL.Create(ASmtp);\n  \/\/ SSL\/TLS handshake determines the highest available SSL\/TLS version dynamically\n  SSLHandler.SSLOptions.Method := sslvSSLv23;\n  SSLHandler.SSLOptions.Mode := sslmClient;\n  SSLHandler.SSLOptions.VerifyMode := [];\n  SSLHandler.SSLOptions.VerifyDepth := 0;\n  ASmtp.IOHandler := SSLHandler;\nend;\n\nprocedure SendMailEx(const AData: TMailSender; AUseSSL, AUseSASL: Boolean);\nvar\n  AMsg: TIdMessage;\n  ASmtp: TIdSmtp;\nbegin\n  AMsg := TIdMessage.Create;\n  ASmtp := TIdSmtp.Create;\n  try\n    AMsg.OnInitializeISO := (AData.Attachements as TMailAttachments)\n      .DoInitializeISO;\n    BuildHtmlMessage(AData, AMsg);\n    if AUseSSL then\n    begin\n      AddSSLSupport(ASmtp);\n      if AData.SMTPPort = 587 then\n        ASmtp.UseTLS := utUseExplicitTLS\n      else\n        ASmtp.UseTLS := utUseImplicitTLS;\n    end;\n    if (Length(AData.UserName) &gt; 0) or (Length(AData.Password) &gt; 0) then\n    begin\n      if AUseSASL then\n      begin\n        ASmtp.AuthType := satSASL;\n        InitSASL(ASmtp, AData.UserName, AData.Password);\n      end\n      else\n      begin\n        ASmtp.UserName := AData.UserName;\n        ASmtp.Password := AData.Password;\n      end;\n    end\n    else\n    begin\n      ASmtp.AuthType := satNone;\n    end;\n\n    ASmtp.Host := AData.SMTPServer;\n    ASmtp.Port := AData.SMTPPort;\n    ASmtp.ConnectTimeout := 30000;\n    ASmtp.UseEHLO := true;\n    ASmtp.Connect;\n    try\n      ASmtp.Send(AMsg);\n    finally\n      ASmtp.Disconnect;\n    end;\n  finally\n    FreeAndNil(ASmtp);\n    FreeAndNil(AMsg);\n  end;\nend;\n\nclass function TMailSender.Create: TMailSender;\nbegin\n  Result := Create(DefaultSMTPServer, DefaultSMTPUserName, DefaultSMTPPassword);\nend;\n\nfunction TMailSender.Send: Boolean;\nbegin\n  try\n    Result := true;\n    SendMailEx(Self, False, UseSASL);\n  except\n    on E: Exception do\n    begin\n      LastError := E.Message;\n      Result := False;\n    end;\n  end;\nend;\n\nfunction TMailSender.SendBySSL: Boolean;\nbegin\n  try\n    Result := true;\n    SendMailEx(Self, true, UseSASL);\n  except\n    on E: Exception do\n    begin\n      LastError := E.Message;\n      Result := False;\n    end;\n  end;\nend;\n\n{ TMailAttachments }\n\nprocedure TMailAttachments.AddFile(const AFileName, AContentId: UnicodeString);\nvar\n  AItem: PMailAttachment;\nbegin\n  New(AItem);\n  AItem.ContentFile := AFileName;\n  AItem.ContentId := AContentId;\n  FItems.Add(AItem);\nend;\n\nprocedure TMailAttachments.AddStream(AData: TStream;\n  const AContentType, AContentId: UnicodeString);\nvar\n  AItem: PMailAttachment;\nbegin\n  New(AItem);\n  AItem.ContentStream := AData;\n  AItem.ContentType := AContentType;\n  AItem.ContentId := AContentId;\n  FItems.Add(AItem);\nend;\n\nconstructor TMailAttachments.Create;\nbegin\n  FItems := TAttachmentList.Create;\nend;\n\ndestructor TMailAttachments.Destroy;\nvar\n  I: Integer;\nbegin\n  for I := 0 to FItems.Count - 1 do\n    Dispose(PMailAttachment(FItems[I]));\n  FreeAndNil(FItems);\n  inherited;\nend;\n\nprocedure TMailAttachments.DoInitializeISO(var VHeaderEncoding: Char;\n  var VCharSet: string);\nbegin\n  VCharSet := 'UTF-8';\n  VHeaderEncoding := 'B';\nend;\n\nfunction TMailAttachments.GetCount: Integer;\nbegin\n  Result := FItems.Count;\nend;\n\nfunction TMailAttachments.GetItems(AIndex: Integer): PMailAttachment;\nbegin\n  Result := FItems[AIndex];\nend;\n\n\/\/\/ &lt;summary&gt;\u68c0\u6d4b\u56fe\u7247\u683c\u5f0f&lt;\/summary&gt;\n\/\/\/ &lt;params&gt;\n\/\/\/ &lt;param name=\"AStream\"&gt;\u8981\u68c0\u6d4b\u7684\u56fe\u7247\u6570\u636e\u6d41&lt;\/param&gt;\n\/\/\/ &lt;\/params&gt;\n\/\/\/ &lt;returns&gt;\u8fd4\u56de\u53ef\u4ee5\u8bc6\u522b\u7684\u56fe\u7247\u683c\u5f0f\u4ee3\u7801&lt;\/returns&gt;\n\nfunction DetectImageFormat(AStream: TStream): TGraphicFormat; overload;\nvar\n  ABuf: array [0 .. 7] of Byte;\n  AReaded: Integer;\nbegin\n  FillChar(ABuf, 8, 0);\n  AReaded := AStream.Read(ABuf[0], 8);\n  AStream.Seek(-AReaded, soFromCurrent); \/\/ \u56de\u5230\u539f\u59cb\u4f4d\u7f6e\n  if (ABuf[0] = $FF) and (ABuf[1] = $D8) then\n    \/\/ JPEG\u6587\u4ef6\u5934\u6807\u8bc6 (2 bytes): $ff, $d8 (SOI) (JPEG \u6587\u4ef6\u6807\u8bc6)\n    Result := gfJpeg\n  else if (ABuf[0] = $89) and (ABuf[1] = $50) and (ABuf[2] = $4E) and\n    (ABuf[3] = $47) and (ABuf[4] = $0D) and (ABuf[5] = $0A) and (ABuf[6] = $1A)\n    and (ABuf[7] = $0A) then\n    Result := gfPng \/\/ 3.PNG\u6587\u4ef6\u5934\u6807\u8bc6 (8 bytes)   89 50 4E 47 0D 0A 1A 0A\n  else if (ABuf[0] = $42) and (ABuf[1] = $4D) then\n    Result := gfBitmap\n  else if (ABuf[0] = $47) and (ABuf[1] = $49) and (ABuf[2] = $46) and\n    (ABuf[3] = $38) and (ABuf[4] in [$37, $39]) and (ABuf[5] = $61) then\n    Result := gfGif\n    \/\/ GIF- \u6587\u4ef6\u5934\u6807\u8bc6 (6 bytes)   47 49 46 38 39(37) 61 G   I   F     8   9 (7)     a\n  else if (ABuf[0] = $01) and (ABuf[1] = $00) and (ABuf[2] = $00) and\n    (ABuf[3] = $00) then\n    Result := gfMetafile \/\/ EMF 01 00 00 00\n  else if (ABuf[0] = $01) and (ABuf[1] = $00) and (ABuf[2] = $09) and\n    (ABuf[3] = $00) and (ABuf[4] = $00) and (ABuf[5] = $03) then\n    Result := gfMetafile \/\/ WMF 01 00 09 00 00 03\n  else if (ABuf[0] = $00) and (ABuf[1] = $00) and\n    ((ABuf[2] = $02) or (ABuf[2] = $10)) and (ABuf[3] = $00) and (ABuf[4] = $00)\n  then\n    Result := gfTga\n    \/\/ TGA- \u672a\u538b\u7f29\u7684\u524d5\u5b57\u8282   00 00 02 00 00,RLE\u538b\u7f29\u7684\u524d5\u5b57\u8282   00 00 10 00 00\n  else if (ABuf[0] = $0A) then\n    Result := gfPcx \/\/ PCX - \u6587\u4ef6\u5934\u6807\u8bc6 (1 bytes)   0A\n  else if ((ABuf[0] = $4D) and (ABuf[1] = $4D)) or\n    ((ABuf[0] = $49) and (ABuf[1] = $49)) then\n    Result := gfTiff \/\/ TIFF  - \u6587\u4ef6\u5934\u6807\u8bc6 (2 bytes)   4D 4D \u6216 49 49\n  else if (ABuf[0] = $00) and (ABuf[1] = $00) and (ABuf[2] = $01) and\n    (ABuf[3] = $00) and (ABuf[4] = $01) and (ABuf[5] = $00) and (ABuf[6] = $20)\n    and (ABuf[7] = $20) then\n    Result := gfIcon \/\/ ICO - \u6587\u4ef6\u5934\u6807\u8bc6 (8 bytes)   00 00 01 00 01 00 20 20\n  else if (ABuf[0] = $00) and (ABuf[1] = $00) and (ABuf[2] = $02) and\n    (ABuf[3] = $00) and (ABuf[4] = $01) and (ABuf[5] = $00) and (ABuf[6] = $20)\n    and (ABuf[7] = $20) then\n    Result := gfCursor \/\/ CUR - \u6587\u4ef6\u5934\u6807\u8bc6 (8 bytes)   00 00 02 00 01 00 20 20\n  else if (ABuf[0] = $46) and (ABuf[1] = $4F) and (ABuf[2] = $52) and\n    (ABuf[3] = $4D) then\n    Result := gfIff \/\/ IFF - \u6587\u4ef6\u5934\u6807\u8bc6 (4 bytes)   46 4F 52 4D(FORM)\n  else if (ABuf[0] = $52) and (ABuf[1] = $49) and (ABuf[2] = $46) and\n    (ABuf[3] = $46) then\n    Result := gfAni \/\/ 11.ANI- \u6587\u4ef6\u5934\u6807\u8bc6 (4 bytes)   52 49 46 46(RIFF)\n  else\n    Result := gfUnknown;\nend;\n\n\/\/\/ &lt;summary&gt;\u68c0\u6d4b\u56fe\u7247\u683c\u5f0f&lt;\/summary&gt;\n\/\/\/ &lt;params&gt;\n\/\/\/ &lt;param name=\"AFileName\"&gt;\u8981\u68c0\u6d4b\u7684\u56fe\u7247\u6587\u4ef6\u540d&lt;\/param&gt;\n\/\/\/ &lt;\/params&gt;\n\/\/\/ &lt;returns&gt;\u8fd4\u56de\u53ef\u4ee5\u8bc6\u522b\u7684\u56fe\u7247\u683c\u5f0f\u4ee3\u7801&lt;\/returns&gt;\nfunction DetectImageFormat(AFileName: String): TGraphicFormat; overload;\nvar\n  AStream: TStream;\nbegin\n  AStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);\n  try\n    Result := DetectImageFormat(AStream);\n  finally\n    FreeAndNil(AStream);\n  end;\nend;\n\nfunction EncodeImageHeader(AStream: TStream; AId, AWidth, AHeight: String)\n  : UnicodeString;\nbegin\n  if Length(AId) &gt; 0 then\n    Result := '&lt;img id=' + QuotedStrW(AId, '\"')\n  else\n    Result := '&lt;img';\n  if Length(AWidth) &gt; 0 then\n    Result := Result + ' width=' + QuotedStrW(AWidth, '\"');\n  if Length(AHeight) &gt; 0 then\n    Result := Result + ' height=' + QuotedStrW(AHeight, '\"');\n  Result := Result + ' src=\"data:image\/';\n  case DetectImageFormat(AStream) of\n    gfBitmap:\n      Result := Result + 'bmp;base64,';\n    gfJpeg:\n      Result := Result + 'jpeg;base64,';\n    gfPng:\n      Result := Result + 'png;base64,';\n    gfGif:\n      Result := Result + 'gif;base64,';\n  else \/\/ \u5176\u5b83\u683c\u5f0f\u5c31\u4e0d\u652f\u6301\u4e86\uff0c\u60f3\u652f\u6301\u7684\u81ea\u5df1\u53c2\u8003\u5904\u7406\n    raise Exception.Create(SUnsupportImageFormat);\n  end;\nend;\n\nfunction EncodeMailImage(AStream: TStream; AId, AWidth, AHeight: UnicodeString)\n  : UnicodeString;\nvar\n  ATemp: TCustomMemoryStream;\nbegin\n  if AStream is TCustomMemoryStream then\n  begin\n    ATemp := AStream as TCustomMemoryStream;\n    Result := EncodeImageHeader(ATemp, '', '', '') +\n      EncodeBase64(PByte(IntPtr(ATemp.Memory) + ATemp.Position),\n      ATemp.Size - ATemp.Position) + '\"&gt;';\n  end\n  else\n  begin\n    ATemp := TMemoryStream.Create;\n    try\n      ATemp.CopyFrom(AStream, AStream.Size - AStream.Position);\n      Result := EncodeImageHeader(ATemp, '', '', '') +\n        EncodeBase64(ATemp.Memory, ATemp.Size) + '\"&gt;';\n    finally\n      FreeAndNil(ATemp);\n    end;\n  end;\nend;\n\nfunction EncodeMailImage(AFileName: UnicodeString;\n  AId, AWidth, AHeight: UnicodeString): UnicodeString;\nvar\n  AStream: TMemoryStream;\nbegin\n  AStream := TMemoryStream.Create;\n  try\n    AStream.LoadFromFile(AFileName);\n    AStream.Position := 0;\n    Result := EncodeImageHeader(AStream, '', '', '') +\n      EncodeBase64(AStream.Memory, AStream.Size) + '\"&gt;';\n  finally\n    FreeAndNil(AStream);\n  end;\nend;\n\nend.<\/pre>\n<p>\u611f\u8c22 BccSafe \u7684\u539f\u521b\uff0c\u9752\u6625\u7b49\u7fa4\u53cb\u7684\u5171\u540c\u6d4b\u8bd5\u3002<\/p>\n<p>\u53d1\u9001\u90ae\u4ef6\u7684\u793a\u4f8b\u4ee3\u7801\uff1a<\/p>\n<pre class=\"lang:delphi decode:true\">var\n  ASender: TMailSender;\nbegin\n  ASender := TMailSender.Create('SMTP\u670d\u52a1\u5668\u5730\u5740', '\u8d26\u53f7','\u5bc6\u7801');\n  ASender.Body := '&lt;html&gt;&lt;body&gt;Hello &lt;B&gt; QDAC &lt;\/B&gt;&lt;\/body&gt;&lt;\/html&gt;';\n  ASender.SenderName := '\u53d1\u9001\u4eba\u59d3\u540d';\n  ASender.SenderMail := '\u53d1\u9001\u8005\u90ae\u7bb1';\n  ASender.RecipientMail := '\u6536\u4ef6\u4eba\u90ae\u7bb1';\n  ASender.Subject := '\u90ae\u4ef6\u4e3b\u9898';\n  \/\/\u5982\u679c\u4e0d\u542f\u7528SSL\uff0c\u5c31\u76f4\u63a5 ASender.Send \u5c31\u53ef\u4ee5\u4e86\u3002\n  ASender.SendBySSL;\nend;<\/pre>\n<p>\u5982\u679c\u8981\u6dfb\u52a0\u9644\u4ef6\uff0c\u5c31\u4f7f\u7528 Attachments \u6210\u5458\u7684 AddFile \u6216 AddStream \u5c31\u884c\u4e86\u3002<\/p>\n<p>\u5982\u679c\u60f3\u5728HTML\u90ae\u4ef6\u4e2d\u63d2\u5165\u56fe\u7247\uff0c\u6709\u4e24\u79cd\u65b9\u5f0f\uff1a<\/p>\n<ol>\n<li>\u6dfb\u52a0\u9644\u4ef6\uff0c\u7136\u540e\u5728\u9644\u4ef6\u4e2d&lt;img src=&#8221;cid:\u9644\u4ef6\u7684ContentId&#8221;&gt;\uff0c\u7f3a\u70b9\u662f\u4f1a\u663e\u793a\u4e3a\u9644\u4ef6\u3002<\/li>\n<li>\u76f4\u63a5\u7528 EncodeMailImage \u63d2\u5165\u57fa\u4e8eBase64 \u7f16\u7801\u7684\u56fe\u7247\u8d44\u6e90\uff0c\u8fd9\u79cd\u4e0d\u4f1a\u663e\u793a\u4e3a\u9644\u4ef6\uff0c\u793a\u4f8b\u5982\u4e0b\uff1a\n<pre class=\"lang:delphi decode:true \">procedure TForm1.Button1Click(Sender: TObject);\nvar\n  ASender: TMailSender;\nbegin\n  ASender := TMailSender.Create; \/\/ \u4f7f\u7528\u5168\u5c40\u7684\u53d1\u9001\u8bbe\u7f6e\n  ASender.Body := '&lt;html&gt;&lt;body&gt;Hello &lt;B&gt; swish &lt;\/B&gt;&lt;br\/&gt;' +\n    EncodeMailImage('D:\\User\\QDAC3\\logo.jpg') + '&lt;\/body&gt;&lt;\/html&gt;';\n  ASender.SenderName := '\u53d1\u9001\u8005\u59d3\u540d';\n  ASender.SenderMail := '\u53d1\u9001\u8005\u90ae\u7bb1\u5730\u5740';\n  ASender.RecipientMail := '\u63a5\u6536\u8005\u90ae\u4ef6\u5730\u5740';\n  ASender.Subject := 'Indy SendMail \u6d4b\u8bd5';\n  ASender.SendBySSL;\nend;<\/pre>\n<p>\u56e0\u4e3a\u4f7f\u7528\u4e86\u5168\u5c40\u7684\u90ae\u4ef6SMTP\u670d\u52a1\u5668\u8bbe\u7f6e\uff0c\u6240\u4ee5\u8bf7\u5148\u8bbe\u7f6e\u597dDefaultSMTPServer\u3001DefaultSMTPUserName \u3001<br \/>\nDefaultSMTPPassword \u4e09\u4e2a\u503c\u3002<\/li>\n<\/ol>\n<p><strong>\u3010\u6ce8\u610f\u3011<\/strong><\/p>\n<p>\u5728 Windows \u4e0b\u5982\u679c\u4f7f\u7528 SSL\uff0c\u9700\u898132\u4f4d\u621664\u4f4d\u7684\u00a0libeay32.dll\u3001ssleay32.dll \u4e24\u4e2a\u52a8\u6001\u94fe\u63a5\u5e93\u53ca\u76f8\u5e94\u7684 VC \u8fd0\u884c\u65f6\u5e93\u652f\u6301\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u3010\u66f4\u65b0\u65e5\u5fd7\u3011 2019.11.18 \u6ce8\u610f [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[69,8,21],"tags":[554,553,552],"class_list":["post-3549","post","type-post","status-publish","format-standard","hentry","category-c-builder","category-delphi","category-misc","tag-smtp","tag-553","tag-552"],"views":5605,"_links":{"self":[{"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=\/wp\/v2\/posts\/3549","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3549"}],"version-history":[{"count":8,"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=\/wp\/v2\/posts\/3549\/revisions"}],"predecessor-version":[{"id":5147,"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=\/wp\/v2\/posts\/3549\/revisions\/5147"}],"wp:attachment":[{"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3549"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3549"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.qdac.cc\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3549"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}