http://www.perlmonks.org?node_id=288914

true has asked for the wisdom of the Perl Monks concerning the following question:

I've got a Linux server running sendmail.
A member signs up in my script. Each member is required to give a valid email address. One of my subroutines sends a message to the new member which verifies whether the address they gave is fully valid and accepting mail. I'm stumped! How can i ask sendmail to send a message and tell me if there was an error without crashing my perl cgi? I've tried MIME::Lite and sendmail. I don't want to mail/forward the error, i just wanted to see a command line reject/error statement. Is this possible? The end goal being a perl script which prints out to the new user a statement telling them there email address is not a valid resolving location and try again. I've tried an "or die" with the open statement below, but no luck.
my %MAIL = (); $MAIL{'TO'} = "NotAcceptingMail@remoteserver.com"; #Brevity exclusion here open (SENDMAIL, '|/usr/sbin/sendmail -oi -t'); print SENDMAIL <<"EOF"; From:<$MAIL{'FROM'}> To:<$MAIL{'TO'}> Subject: $MAIL{'SUBJECT'} $MAIL{'BODY'} EOF close (SENDMAIL);
thanks for reading,

Replies are listed 'Best First'.
•Re: Sendmail to non-working email address
by merlyn (Sage) on Sep 04, 2003 at 17:11 UTC
    You can verify whether the syntax of an email address is valid with Email::Valid (and friends).

    But to verify whether it's semantically valid can be done only one way... send email to the address with a unique token, and have them return it (in a way that's not a bounce message) or visit a web site.

    There is no real-time way to do that. You'll get both false positives and false negatives. As a specific example, there is no way you can verify that jeffrey.dahmer@stonehenge.com is a valid email address in real time. You have to just send it. And you'll either get a bounce later, or a response.

    I have an example of doing that for mod_perl, and an older version for CGI.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Sendmail to non-working email address
by hardburn (Abbot) on Sep 04, 2003 at 16:47 UTC

    Wrap your sendmail portions in an eval block:

    eval { open (SENDMAIL, '|/usr/sbin/sendmail -oi -t'); print SENDMAIL <<"EOF"; From:<$MAIL{'FROM'}> To:<$MAIL{'TO'}> Subject: $MAIL{'SUBJECT'} $MAIL{'BODY'} EOF close (SENDMAIL); }; if($@) { print "Something went wrong!\n"; }

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    Note: All code is untested, unless otherwise stated

Re: Sendmail to non-working email address
by jdtoronto (Prior) on Sep 04, 2003 at 16:56 UTC
    Hi,

    You should think of this the other way around. Validate the address before you attempt to send to it, that way you have some hope of catching the error early.

    There are a number of CPAN modules, I have used this one Mail::CheckUser very succesfully in several products.

    However, you should bear in mind that some of the larger ISP's do not reject at the SMTP connection, they receive the email, then send back a bounce message later. You really need to make the data persistent - ie, some session management and a database maybe - in order to ensure that you get valid email.

    In fact, depending on what you are doing, you should possibly accept the unverifiable email, then send an email with a non-trivial nonce requiring that they respond to it - maybe to a script - in order to be signed up for whatever it is.

    jdtoronto

Re: Sendmail to non-working email address
by blue_cowdawg (Monsignor) on Sep 04, 2003 at 17:14 UTC

    Having solved this issue a time or three let me share some thoughts with you:

    Is this address valid?

    First off consider looking at Email::Valid. This module will do two things for you. First it will check to see if the address is well formed. Seondly it checks to see if there is a mail server for the domain part. Example:

    --$ perl -MEmail::Valid printf "%s\n",(Email::Valid->address("peter\@berghold.net")?"Yes":"no" +); Yes --$ perl -MEmail::Valid printf "%s\n",(Email::Valid->address("peter@yuckster.com")?"Yes":"no") +; no --$ host yuckster.com yuckster.com has address 216.21.229.209 --$ host -tany yuckster.com yuckster.com name server dns21.register.com. yuckster.com name server dns22.register.com. yuckster.com has address 216.21.229.209

    With that information in hand I can go to the next step in validating this user's email address.

    But do they have a valid account at that address?

    Here is here I get really clever. (well... maybe not that clever..) First some assumptions:

    1. I have an RDBMS I can shove info into or a reasonable facimile
    2. I can generate unique keys for the user's email address and a link to a page to validate that unique key
    After recording the key and email address somewhere for my validation script to find it I send the user an email that will have a key and a link to a page. I will either have the user type in the key (yuck!) or I will provide them with a link to a CGI script that takes the email address and key as parameters to be validated. The URL that I email them will look something like:
    http://my.server.com/cgi-bin/validate.cgi?key=oiweruojaklsdfklh&email= +dude@isp.com

    Now you have validated that the email address is valid AND you have validated that it exists... Like it? There is more than one way to do this, but this is one of them.


    Peter L. Berghold -- Unix Professional
    Peter at Berghold dot Net
       Dog trainer, dog agility exhibitor, brewer of fine Belgian style ales. Happiness is a warm, tired, contented dog curled up at your side and a good Belgian ale in your chalice.
Re: Sendmail to non-working email address
by dtr (Scribe) on Sep 04, 2003 at 18:13 UTC

    OK - the problem here is that you're underestimating the complexity of what you're asking.

    First of all, you cannot guarantee that you can get to the authoritative mail server for someone's email from the internet. For example, they may run an e-mail gateway which does virus checking before forwarding onto the real mail server (like messagelabs, or a home grown equivelant), their main mail server may be down, and you'll get through to a backup mail server (a temp spool only, which forwards to the primary e-mail server once it comes back online), or maybe others!

    Secondly, piping out to sendmail will return success if sendmail accepts the message - not if sendmail can deliver it. If sendmail cannot deliver the message, it'll give up later, and send a DSN to the sender (you wouldn't want to wait until sendmail times out before continuing in your code, would you :)

    In short, you have two options:-

    1. Attempt to deliver the message, set the from address to somehting that'll get delivered back to a POP account, and use Net::POP to check the POP account for DSNs or other failures (RFC-1894 is your friend here)
    2. Send the member an e-mail address before enabling their account. If they click on a link in the e-mail (include their user-id, and some authentication details), they call a CGI which will then enable their account

    I personally think that (2) is the safest, easiest, and most reliable, as long as you're willing to run a nightly cron job to clear out any old accounts that haven't been activated within X days.

Re: Sendmail to non-working email address
by true (Pilgrim) on Sep 04, 2003 at 17:41 UTC
    I tried the eval statement and got the same result. If i send a message to an address that is not accepting mail, my script crashes and the user sees Internal Server Error on their screen. If i can prevent this from happening, my problem is solved.

    My message is generated from my server perl.to and sent to the address bad@perl.to. My catch-all's are OFF and only mail sent to specific users specified in my virtusertable will be accepted. I need a perl script to attempt to send this message and:

    1. Not crash the perl cgi.
    2. give me an error message i can translate

    If i can only get number one i can live with it. Thanks for reading and thanks for all the advice. I hope this post streamlines my question a little bit.

    jtrue

      If you're trying to verify users e-mail addresses on your machine then don't do this at all--check your local user database instead. If you don't have one, make one. (And odds are you do have one, you just need to find it. What, where, and how depends on your system)

      (If you're looking to verify addresses on other machines in realtime, you can't. Stop trying, it's impossible in general and all you'll do is make a mess of things, probably leave a spam and/or abuse hole, and piss people off)

Re: Sendmail to non-working email address
by true (Pilgrim) on Sep 04, 2003 at 18:27 UTC
    Ok, this is my best solution so far. I'm using open2. Now i get a response when i send a mail to a bad address (bad meaning the remote server is not accepting mail for the address given). This tested fine under RedHat 7.2.
    sub SendMail{ my %MAIL = @_; my $RESULT = "SendMail to".$MAIL{'TO'}; use IPC::Open2; open2(*READA,*WRITEA,"/usr/lib/sendmail -oi -t"); print WRITEA "To:$MAIL{'TO'}\n"; print WRITEA "From:$MAIL{'FROM'}\n"; print WRITEA "Subject:$MAIL{'SUBJECT'}\n\n"; print WRITEA "$MAIL{'BODY'}\n"; close WRITEA; while ($line = <READA>){$RESULT .= "<li>$line\n";} close READA; return $RESULT; }############################ end SendMail
    jtrue
      Where do you get the parameters to this subroutine? Please dear gawd, don't say "from a web form". Argh!

      If so, you've just created a spam engine.

      Have you actually read any of the answers to your post? You appear to be ignoring the fundamental problem.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

      Please try your test with @aol.com addresses.

      Last time I heard AOL accepts ALL email address to the aol.com domain, and deals with dumping it later.

      Please correct me if I'm wrong.

      IMHO the only method that works are the procedures blue_cowdawg and merlyn outlined.

      The user must receive an email with a Unique identifer, and respond with that secret and unique "key" (preferable non-guessable and random).
        Hi smellysocks!

        The only time AOL does not accept the message is if originating machine is in their black list - then they 550 it at the connection. Otherwise they accept and notify in the bounce message as you surmise.

        jdtoronto

Re: Sendmail to non-working email address
by true (Pilgrim) on Sep 05, 2003 at 15:03 UTC
    One clarification i have realized was important if anyone else has the same problem. My internal server errors were generated only from mailing addresses from WITHIN my server. So a message from one virtual host to another virtual host is what was causing the cgi to crash. The open2 solution is still in place and does not 500 when mailing to a bad address. yeah!

    Also, sendmail was reporting a bad header and dropping the bad address in a dead.letter file. By using open2 my perl script can easily read this error and report to the user the problem. This saves my script a lot of time and gives me the most information. Thanks monks.

    jtrue