Look up if Mail Server exists for list of emails
is there a simple way to look up if a domain has a MX record or not using Delphi? I have a list of emails that I wish to verify work, I want to check each of the domains and see if a MX server even exists.
Thanks.
Edit: The email addresses I have are all from bounced email messages of error code: 5.4.0. But too many servers don't follow any standards and 5.4.0 error code itself can mean too much. I don't want to just remove all the email addresses found with that error code erroraneously, so I figure a better way is t开发者_开发技巧o first check if the domain or mx record don't exist and remove those for sure.
You can use the windows DnsQuery API to check the MX records for a given server name. Unfortunately I didn't find a proper Delphi translation for the headers, so I made a partial (but workable) translation myself. It only supports MX and IpV4 A records, nothing else. Adding support for IpV6 address should be trivial.
Here's my translation, including a simple ServerHasMxRecords(const ServerName:string):Boolean
function that returns True
if any MX records are found:
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.
It is actually good to have an e-mail checker. If nothing else you can clean you e-mail base and avoid sending over and over to non existing mails. Or you can use it as means of verifying user mails when they sign on to your application.
Here is a part of the code in my mail checking class.
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;
Basically you do it in three steps:
- Check the mail syntax.
- Check the domain and validate MX server
- Validate the user mailbox
The only way to check if you can deliver an email is to actually deliver it, and check the zillion ways you can get a bounce response.
精彩评论