Посмотрите, существует ли Почтовый сервер для списка писем - PullRequest
3 голосов
/ 22 июня 2011

Есть ли простой способ узнать, есть ли у домена запись MX или нет использования Delphi? У меня есть список электронных писем, которые я хочу проверить, я хочу проверить каждый из доменов и посмотреть, существует ли сервер MX.

Спасибо.

Редактировать: все мои адреса электронной почты взяты из сообщений электронной почты с ошибкой: 5.4.0. Но слишком много серверов не соответствуют никаким стандартам, а сам код ошибки 5.4.0 может означать слишком много. Я не хочу просто ошибочно удалять все адреса электронной почты, найденные с этим кодом ошибки, поэтому я считаю, что лучше сначала проверить, не существует ли запись домена или mx, и удалить их наверняка.

Ответы [ 3 ]

2 голосов
/ 23 июня 2011

Вы можете использовать Windows DnsQuery API, чтобы проверить записи 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.
1 голос
/ 23 июня 2011

На самом деле хорошо иметь проверку электронной почты. Если ничего другого, вы можете почистить свою почтовую базу и избегать пересылки на несуществующие письма. Или вы можете использовать его как средство проверки почты пользователя при входе в ваше приложение.

Вот часть кода в моем классе проверки почты.

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;

Обычно вы делаете это в три этапа:

  1. Проверьте синтаксис почты.
  2. Проверка домена и проверка MX-сервера
  3. Проверка почтового ящика пользователя
1 голос
/ 22 июня 2011

Единственный способ проверить, можете ли вы доставить электронное письмо, состоит в том, чтобы фактически доставить его, и проверить миллионы способов получения отказов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...