[aur-dev] [PATCH] validate email and fully check existence of it

Florian Pritz bluewind at xinu.at
Tue Mar 20 07:15:11 EDT 2012


On 20.03.2012 10:36, BlackEagle wrote:
> - check if the format is valid
> - go and connect to the smtp server of the given domain and verify if
>   the given email exists there

Good idea, but I've seen mail servers accepting all recipients during
the SMTP session, but later sending a DSN because the user didn't exist.
That means we should still implement verification emails. Having this
check is still good though.

> ---
>  web/lib/aur.inc.php |   75 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 74 insertions(+), 1 deletions(-)
> 
> diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php
> index c662b80..3fc0a14 100644
> --- a/web/lib/aur.inc.php
> +++ b/web/lib/aur.inc.php
> @@ -80,7 +80,80 @@ function check_sid($dbh=NULL) {
>  # verify that an email address looks like it is legitimate
>  #
>  function valid_email($addy) {
> -	return (filter_var($addy, FILTER_VALIDATE_EMAIL) !== false);
> +    // check against RFC 3696
> +    if(filter_var($addy, FILTER_VALIDATE_EMAIL) === false) {
> +        return false;
> +    }
> +
> +    // check dns for mx, a, aaaa records
> +    list($local, $domain) = explode('@', $addy);
> +    if(! (checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A') || checkdnsrr($domain, 'AAAA'))) {

Please display an error message if this fails.

> +        return false;
> +    }
> +
> +    // get mx records and check full email address
> +    $mxlist = array();
> +    $mxweight = array();
> +    getmxrr($domain, $mxlist, $mxweight);

http://php.net/getmxrr#refsect1-function.getmxrr-notes states:
"This function should not be used for the purposes of address
verification. Only the mailexchangers found in DNS are returned ..."

> +    $mx = array_combine($mxweight, $mxlist);
> +    ksort($mx);
> +
> +    //smtp_test_email($addy, current($mx));
> +    foreach($mx as $prio => $mxsrv) {
> +        if(smtp_test_email($addy, $mxsrv) === true) {
> +            return true;
> +        }
> +    }

Since this will eventually return false negatives, please display all
SMTP sessions if you get here. This will help users understand what went
wrong so they can fix it more easily.

> +
> +    return false;
> +}
> +
> +# verify that an email address exists on the smtp server
> +#
> +function smtp_test_email($addy, $mxsrv) {
> +    if(($smtp = fsockopen($mxsrv, 25)) === false) {
> +        return false;
> +    }
> +
> +    if(intval(preg_replace('/^\([0-9]{3}\).*/', '\1', fgets($smtp))) !== 220) {
> +        smtp_close($smtp);
> +        return false;
> +    }
> +
> +    fwrite($smtp, "HELO $mxsrv\r\n");

HELO should send the client name, not the server name.

> +    if(intval(preg_replace('/^\([0-9]{3}\).*/', '\1', fgets($smtp))) !== 250) {
> +        smtp_close($smtp);
> +        return false;
> +    }
> +
> +    fwrite($smtp, "MAIL FROM: <mailtest at archlinux.org>\r\n");
> +    if(intval(preg_replace('/^\([0-9]{3}\).*/', '\1', fgets($smtp))) !== 250) {
> +        smtp_close($smtp);
> +        return false;
> +    }
> +
> +    fwrite($smtp, "RCPT TO: <$addy>\r\n");
> +    $code = intval(preg_replace('/^\([0-9]{3}\).*/', '\1', fgets($smtp)));
> +    /**
> +     * 250 = success
> +     * 451 or 452 = address got greylisted but another error occured

s/got/not/?

> +     *              so assume ok
> +     */
> +    if($code !== 250 && $code !== 451 && $code !== 452) {

I'm not sure if rejecting greylisted adresses is a good idea because
that means the users have to resubmit the form after 5-30 minutes. You
should ask them to confirm that their address is correct (typo catching)
and then ignore all temporary errors (all 4xx codes). If you get a 5xx
it's fine to abort.

If you want to make sure the address really exists, you have to
implement verification mails. Just checking return codes for RCPT TO is
not enough.

> +        smtp_close($smtp);
> +        return false;
> +    }
> +
> +    smtp_close($smtp);
> +    return true;
> +}
> +
> +# close smtp conneciton
> +#
> +function smtp_close(&$smtp) {
> +    fwrite($smtp, "RSET\r\n");
> +    fwrite($smtp, "QUIT\r\n");
> +    fclose($smtp);
>  }
>  
>  # a new seed value for mt_srand()


-- 
Florian Pritz

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: OpenPGP digital signature
URL: <http://mailman.archlinux.org/pipermail/aur-dev/attachments/20120320/48974454/attachment-0001.asc>


More information about the aur-dev mailing list