有沒有簡單的方法來查看域名是否有MX記錄或不使用Delphi?我有一個我希望驗證工作的電子郵件列表,我想檢查每個域並查看是否存在MX服務器。查找郵件服務器是否存在電子郵件列表
謝謝。
編輯:我有的電子郵件地址全部來自錯誤代碼:5.4.0的退回電子郵件。但太多的服務器不遵循任何標準,5.4.0錯誤代碼本身可能意味着太多。我不想僅僅刪除所有使用該錯誤代碼發現的電子郵件地址,所以我想一個更好的方法是首先檢查域或mx記錄是否不存在,然後刪除這些地址。
有沒有簡單的方法來查看域名是否有MX記錄或不使用Delphi?我有一個我希望驗證工作的電子郵件列表,我想檢查每個域並查看是否存在MX服務器。查找郵件服務器是否存在電子郵件列表
謝謝。
編輯:我有的電子郵件地址全部來自錯誤代碼:5.4.0的退回電子郵件。但太多的服務器不遵循任何標準,5.4.0錯誤代碼本身可能意味着太多。我不想僅僅刪除所有使用該錯誤代碼發現的電子郵件地址,所以我想一個更好的方法是首先檢查域或mx記錄是否不存在,然後刪除這些地址。
實際上有一個電子郵件檢查器是很好的。如果沒有其他的東西可以清理你的電子郵件庫,並避免一遍又一遍地發送到非現有的郵件。或者,您可以將它用作驗證用戶郵件的方式,當他們登錄到您的應用程序。
這是我的郵件檢查課程的一部分代碼。
procedure TMailValidator.ResolveEmailAddress(const Address: TEMailAddress; const DNSServer: string);
var
I: Integer;
MXEmpty: Boolean;
DomainName: string;
DNSResolver: TIdDNSResolver;
begin
DNSResolver := TIdDNSResolver.Create(nil);
try
DomainName := StrAfter('@', string(Address));
MXEmpty := True;
DNSResolver.Host := DNSServer;
{$IFNDEF IT_UseIndy9}
DNSResolver.QueryType := [qtMx];
{$ELSE}
DNSResolver.QueryRecords := [qtMx];
{$ENDIF} // IT_UseIndy9
try
{$IFNDEF IT_UseIndy9}
DNSResolver.WaitingTime := FDNSResolveTimeout;
{$ELSE}
DNSResolver.ReceiveTimeout := FDNSResolveTimeout;
{$ENDIF} // IT_UseIndy10
DNSResolver.Resolve(DomainName);
for I := 0 to DNSResolver.QueryResult.Count - 1 do
begin
if DNSResolver.QueryResult[I].RecType = qtMX then
begin
MXEmpty := False;
CheckEmailAddress(Address, TMXRecord(DNSResolver.QueryResult[I]).ExchangeServer);
// were we successfull
if CheckSMTPExitErrorCode then
Exit;
end;
end;
// check for servers flag
if FFoundMailServer then
begin
SendLogMessage(Format('Address "%s" is not valid on domain "%s"', [Address, DNSServer]));
SetLastError(cUserErrorCodeBase + 5);
end
else
begin
if MXEmpty then
begin
SendLogMessage(Format('No valid mail(MX) server could be found for domain "%s"', [DomainName]));
CheckEmailAddress(Address, DomainName);
end
else
begin
SendLogMessage(Format('Mail server did not respond on domain "%s"', [DomainName]));
SetLastError(cUserErrorCodeBase + 3);
end;
end;
except
on E: Exception do
begin
SendLogMessage(Format('Address "%s" validation failed for domain "%s": %s', [Address,
DomainName,
E.Message]));
SetLastError(cUserErrorCodeBase + 4, E.Message);
end;
end;
finally
DNSResolver.Free;
end;
end;
procedure TMailValidator.CheckEmailAddress(const Address: TEMailAddress; const MailServer: string);
var
SMTP: TIdSMTP;
begin
SendLogMessage(Format('Validating address "%s" on server "%s"', [Address, MailServer]));
if (FCheckStep = csAddress) or (FCheckStep = csDomain) then
begin
// finish if flags in [FLAG_CheckLocal, FLAG_CheckDomain]
SendLogMessage(Format('Address "%s" successfuly validated.', [Address]));
Exit;
end;
SMTP := TIdSMTP.Create(nil);
try
FCurrentStep := csMailBox;
try
SMTP.ReadTimeout := FSMTPReadTimeout;
{$IFNDEF IT_UseIndy9}
SMTP.AuthType := satNone;
{$ELSE}
SMTP.AuthenticationType := atNone;
{$ENDIF} // IT_UseIndy9
SMTP.Host := MailServer;
SMTP.Port := 25;
SMTP.Connect;
try
FFoundMailServer := True;
try
SMTP.SendCmd('Helo ' + FQueryingServer, 250);
SMTP.SendCmd('Rset');
SMTP.SendCmd('Mail from:<' + string(Address) + '>', 250);
SMTP.SendCmd('RCPT to:<' + string(Address) + '>', [250, 251]);
SendLogMessage(Format('Address "%s" successfuly validated on server "%s".', [FEMailAddress,
MailServer]));
except
on E: Exception do
begin
SendLogMessage(Format('Address "%s" validation failed on server "%s": %s', [Address,
MailServer,
E.Message]));
SetLastError(SMTP.LastCmdResult.NumericCode, E.Message);
Exit;
end;
end
finally
SMTP.Disconnect;
end;
except
// handle all other exceptions
on E: Exception do
begin
SendLogMessage(Format('CheckMail [%s] : Failure (Server) "%s" [%s]', [Address,
MailServer,
E.Message]));
SetLastError(Max(cUserErrorCodeBase + 6, SMTP.LastCmdResult.NumericCode), E.Message);
end;
end;
finally
SMTP.Free;
end;
end;
基本上你做的三個步驟:
成功完成步驟#3並不意味着郵箱有效,而只是表示郵件服務器可能接受該地址的郵件。郵件服務器可能會在發送數據後拒絕該郵件,或者可能會愉快地接受來自您的郵件,然後再轉向並刪除它。 – afrazier
另外,特別挑剔的人可能不喜歡你使用異常來進行常見錯誤控制/代碼流的目的。錯誤的電子郵件地址,失敗的主機,完整的郵箱等不是*例外情況。 :-)(我不打算聲稱自己完全清楚那個特定代碼的味道) – afrazier
我沒有提出異常,只設置了最後的錯誤代碼。最後你只檢查整個過程的錯誤代碼。此外,我必須捕捉Indy異常,因爲Indy使用異常來處理代碼流。我也不喜歡那樣。我只是在做Windows API所做的事情 – Runner
你可以使用windows API DnsQuery檢查MX記錄給定的服務器名稱。不幸的是,我沒有找到適合的頭文件的Delphi翻譯,所以我自己做了部分(但可行)的翻譯。它只支持MX和IpV4 A記錄,沒有別的。添加對IpV6地址的支持應該是微不足道的。
這裏是我的翻譯,包括一個簡單的ServerHasMxRecords(const ServerName:string):Boolean
函數返回True
如果任何MX記錄發現:
unit DnsMxCheck;
interface
uses Windows, Classes;
type
DNS_STATUS = Integer;
IP4_ADDRESS = DWORD;
_DNS_RECORD_FLAGS = packed record
case Boolean of
True: (DW: DWORD);
False: (DNS_RECORD_FLAGS: DWORD);
end;
DNS_A_DATA = packed record
case Boolean of
True: (IpAddress: IP4_ADDRESS);
False: (Bytes:array[0..3] of Byte);
end;
DNS_MX_DATA = packed record
pNameExchange: PWChar;
wPreference: Word;
Pad: Word;
end;
_DNS_RECORD_DATA_UNION = packed record
case Integer of
0: (A: DNS_A_DATA);
1: (MX1, MX2, AFSDB1, AFSDB2, RT1, RT2: DNS_MX_DATA);
999: (Filler: array[0..1024] of Byte); // I have no idea what the true size of the record shoud be!
end;
PDNS_RECORD = ^DNS_RECORD;
DNS_RECORD = packed record
NextRecord: PDNS_RECORD;
pName: PWChar;
wType: Word;
wDataLength: Word;
Flags: _DNS_RECORD_FLAGS;
dwTtl: DWORD;
dwReserved: DWORD;
Data: _DNS_RECORD_DATA_UNION;
end;
const DNS_TYPE_A = $0001;
DNS_TYPE_MX = $000f;
function DnsQuery_W(lpstrName: PWChar; wType: Word; Options: DWORD; pExtra: Pointer; out ppQueryResultsSet: PDNS_RECORD; pReserved: Pointer): DNS_STATUS;stdcall;external 'dnsapi.dll';
function ServerHasMxRecords(const ServerName:string):Boolean;
implementation
function ServerHasMxRecords(const ServerName:string):Boolean;
var DNS_REC: PDNS_RECORD;
begin
if DnsQuery_W(PWChar(ServerName), DNS_TYPE_MX, 0, nil, DNS_REC, nil) = 0 then
begin
while Assigned(DNS_REC) do
begin
if DNS_REC.wType = DNS_TYPE_MX then
begin
Exit(True);
end;
DNS_REC := DNS_REC.NextRecord;
end;
end;
Result := False;
end;
end.
千萬牢記的是(A)僅僅因爲這個域有一個MX記錄,它不意味着指定的服務器將接收您感興趣的地址的郵件,並且(b)缺少MX記錄並不意味着無法發送到該地址的郵件(大多數MTA會回退到嘗試將域名解析爲IP地址。) –
哇,這聽起來像是一個垃圾郵件發送者會問的問題。 :-) –
這實際上是一個通訊。但是,是的,我猜想的前提是一樣的。 –