之前一直使用非加密的方式发送邮件(使用的QQ邮箱 25端口),但是2024年11月24日之后,发现发送邮件时都返回提示(如下);大致问题应该就是需要使用加密端口465才能继续发送;找了较多的资料,居然都用不了;而且资料很少,还有个家伙直接提交的一个Exe,哎~~~ 要有共享精神好么~~!!
Login fail. A secure connection is requiered(such as ssl). More information at https://help.mail.qq.com/detail/0/1010
JavaScript以下是DelphiXE11发送邮件的完整代码,大家可以直接使用;如果使用低版本的,调整以下引用头
unit uEMail;
interface
uses
System.SysUtils, Classes, IdMessage, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdExplicitTLSClientServerBase, IdMessageClient,
IdSMTPBase, IdSMTP, IdIOHandler, IdAttachment, IdAttachmentFile, System.IniFiles,
IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdSSLOpenSSLHeaders,
System.RegularExpressions, IdAntiFreezeBase, IdAntiFreeze;
type
//邮件发送状态
TEMailSendState = (TEMSS_WaitSend = 0,
TEMSS_Error = 1,
TEMSS_Succ = 2,
TEMSS_Failed = 3
);
type
TMailSetting = record
Host : string; //邮件发送服务器
Port : Integer; //端口
UserName : string; //邮箱登录帐号
UserPassWord : string; //邮箱登录密码
SenderName : string; //发送人
FilePath : string; //附件文件路径
end;
var
Consignees : Tstringlist; //接收人列表
IdAntiFreeze:TIdAntiFreeze;
IdSMTP : TIdSMTP;
IdMessage : TIdMessage;
GMailSetting : TMailSetting;
fIdSSL : TIdSSLIOHandlerSocketOpenSSL;
iResult: boolean;
function LoadIni:boolean;
function CheckEmailAdress(const EmailAddr: string): Boolean;//验证Email
{-------------------------------------------------------------------------------
过程名: SendEmail
作用:
作者: Chrysalis(QQ:342667266)
日期: 2024.12.05
参数: _Recipients : string; 收件人列表 英文分号进行分割,支持多个
_Subject:string; 邮件发送的标题
_Content:string; 邮件发送的内容
_AttachList:string; 附件列表 完整路径 英文分号进行分割,支持多个
var sErr:string 发送邮件失败时的错误
返回值: TEMailSendState
-------------------------------------------------------------------------------}
function SendEmail(_Recipients : string; _Subject, _Content, _AttachList:string; var sErr:string):TEMailSendState;
implementation
uses
uPubFunc ;
function LoadIni:boolean;
var
fFile: TIniFile;
begin
fFile := TIniFile.Create(GetCurrentDir + '\Config.ini');
try
with GMailSetting do
begin
Host := fFile.ReadString('EMAIL','Host','smtp.qq.com');
Port := fFile.ReadInteger('EMAIL','Port',25);
UserName := fFile.ReadString('EMAIL','UserName','00000000@qq.com');
UserPassWord := fFile.ReadString('EMAIL','UserPassWord','');
SenderName := fFile.ReadString('EMAIL','SenderName','00000000@qq.com');
FilePath := fFile.ReadString('EMAIL','FilePath', ExtractFilePath(ParamStr(0)) + 'files\email\');
end;
finally
freeandnil(fFile);
end;
end;
//验证Email
function CheckEmailAdress(const EmailAddr: string): Boolean;
const
EMAIL_REGEX = '^((?>[a-zA-Z\d!#$%&''*+\-/=?^_`{|}~]+\x20*|"((?=[\x01-\x7f])' + '[^"\\]|\\[\x01-\x7f])*"\x20*)*(?<angle><))?((?!\.)' + { }
'(?>\.?[a-zA-Z\d!#$%&''*+\-/=?^_`{|}~]+)+|"((?=[\x01-\x7f])[^"\\]|\\[\x01-\x7f])*")@(((?!-)[a-zA-Z\d\-]+(?<!-)\.)+[a-zA-Z]' + { }
'{2,}|\[(((?(?<!\[)\.)(25[0-5]|2[0-4]\d|[01]?\d?\d)){4}|[a-zA-Z\d\-]*[a-zA-Z\d]:((?=[\x01-\x7f])[^\\\[\]]|\\[\x01-\x7f])+)\])(?(angle)>)$';
begin
try
Result := TRegEx.IsMatch(EmailAddr, EMAIL_REGEX);
finally
end;
end;
//发送邮件
function SendEmail(_Recipients : string; _Subject, _Content, _AttachList:string; var sErr:string):TEMailSendState;
var
sRealRecipients, _sFilePath : string;
idAtta : TIdAttachmentFile;
I: Integer;
sList, _AList : TStringList;
begin
Result := TEMSS_Error;
if Trim(_Recipients) = '' then Exit;
//检查发送列表有效性,踢出无效的,发送有效的
sErr := '';
sRealRecipients := '';
//按英文分号进行分割
sList := TStringList.Create;
try
if not SplitString(Trim(_Recipients), sList, ';') then
sErr := sErr + '[通知邮件地址] 填写有问题' + #13
else
begin
if sList.Count > 10 then
sErr := sErr + '[通知邮件地址] 不能超过10个地址' + #13
else
begin
for I := 0 to sList.count - 1 do
begin
if Trim(sList.Strings[I]) = '' then Continue;
if not CheckEmailAdress(Trim(sList.Strings[I])) then
sErr := sErr + Format('电子邮件地址 [%s] 格式不正确',[Trim(sList.Strings[I])]) + #13
else
begin
if pos(Trim(sList.Strings[I]), sRealRecipients) = 0 then
sRealRecipients := sRealRecipients + Trim(sList.Strings[I]) + ';';
end;
end;
end;
end;
finally
sList.Free;
end;
if sRealRecipients = '' then Exit;
if not Assigned(IdMessage) then Exit;
if not Assigned(IdSMTP) then Exit;
IdSMTP.Host := GMailSetting.Host;
IdSMTP.Port := GMailSetting.Port;
IdSMTP.Username := GMailSetting.UserName;
IdSMTP.Password := GMailSetting.UserPassWord;
IdSMTP.AuthType := satDefault ; //如果邮箱服务器需要身份验证,需要这句;
IdSMTP.ValidateAuthLoginCapability := True;
IdSMTP.UseTLS := utUseImplicitTLS; //支持邮件发送SSL
IdMessage.Body.Clear; // 先清空上次发送的内容
IdMessage.MessageParts.Clear; // 先清空上次发送的附件
IdMessage.CharSet :='GB2312'; //不设置这个中文会乱码
IdMessage.Priority := mpHigh; //优先级
IdMessage.From.Address := GMailSetting.UserName; //设置发件人
IdMessage.Recipients.EMailAddresses := _Recipients; //设置收件人
IdMessage.Subject := _Subject; //设置邮件发送的标题
IdMessage.Body.Text := _Content; //设置邮件发送的内容
//解析附件列表
if _AttachList <> '' then
begin
//按英文分号进行分割
_AList := TStringList.Create;
try
_AList.StrictDelimiter := True ; //排除空格的方式
_AList.Delimiter := ';';
_AList.DelimitedText := _AttachList;
if _AList.Count <= 0 then Exit;
for I := 0 to _AList.count - 1 do
begin
if Trim(_AList.Strings[I]) = '' then Continue;
//检查需要发送的附件是否存在
_sFilePath := GMailSetting.FilePath + Trim(_AList.Strings[I]);
if FileExists(_sFilePath) then
begin
idAtta := TIdAttachmentFile.Create(IdMessage.MessageParts, _sFilePath); //附件
idAtta.ContentType := 'application/octet-stream';
idAtta.ContentDisposition := 'attachment';
idAtta.ContentTransfer := 'base64';
idAtta.FileIsTempFile := False; //非临时文件,不需要删除
idAtta.FileName := ExtractFileName(Trim(_AList.Strings[I]));
end;
end;
finally
_AList.Free;
end;
end;
try
try
IdSMTP.Connect;
IdSMTP.Authenticate; //登录验证
if IdSMTP.Connected then
begin
IdSMTP.Send(IdMessage);
Result := TEMSS_Succ;
end
else
begin
Result := TEMSS_Error;
end;
except
on E:Exception do
begin
Result := TEMSS_Error;
sErr := Format('发送邮件时发生错误 - %s',[E.Message]);
end;
end;
finally
if IdSMTP.Connected then
begin
IdSMTP.Disconnect(True);
end;
end;
end;
initialization
IdAntiFreeze := TIdAntiFreeze.Create(nil);
IdSMTP := TIdSMTP.Create(nil);
IdMessage := TIdMessage.Create(nil);
LoadIni;
fIdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
fIdSSL.SSLOptions.Method := sslvSSLv23;
fIdSSL.SSLOptions.Mode := sslmClient;
IdSMTP.IOHandler := fIdSSL;
// iResult := IdSSLOpenSSLHeaders.Load();
finalization
if Assigned(IdMessage) then
IdMessage.Free;
if Assigned(IdSMTP) then
IdSMTP.Free;
if Assigned(fIdSSL) then
fIdSSL.Free;
if Assigned(IdAntiFreeze) then
IdAntiFreeze.Free;
end.
JavaScript引用前需要先配置一个配置文件Config.ini,自行修改函数也可以
Host 填写邮件服务器的地址,我这里使用的是QQ邮箱
Port 填写邮件服务器的SSL端口,QQ邮箱的SSL端口就是465; 非SSL端口是25
UserName 填写QQ邮箱账号
UserPassWord 填写授权码; 这个要特别注意,不是填你QQ邮箱的密码
SenderName 填写QQ邮箱账号和UserName一致即可
格式如下
[EMAIL]
Host=smtp.qq.com
Port=465
UserName=00000000@qq.com
UserPassWord=XXXXXXXXXXXXXX
SenderName=00000000@qq.com
JavaScript使用方法
//引用方法 先调用 LoadIni 加载默认参数 我默认时当前路径的Config.ini
//程序初始化时调用一次
LoadIni
//后续在需要发送邮件时调用
SendEmail('1234567@qq.com;43212@qq.com',
'这个是标题',
'这个是内容',
'c:/test.txt;c:/ok.txt;',
sErr
)
JavaScript另外说一下使用25端口非加密方式发送邮件的方法,很简单;把上面代码中屏蔽如下代码,配置文件中的port修改为25即可;
IdSMTP.UseTLS := utUseImplicitTLS; //支持邮件发送SSL
JavaScript祝各位好运