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

I'm trying to make a script that it will get data from submit of some forms and send the data to a specific mail account. On the machine that the script will run i cannot add modules so i must use IO::Socket;

my code is:

#!/usr/bin/perl use IO::Socket; $socket=IO::Socket::INET->new(PeerAddr => localhost, PeerPort => "25", Proto => "tcp" ) or die "MAIL: $!"; print $socket "MAIL FROM: <somebody>", "\n"; print $socket "RCPT TO: <xxx@xxxxxxxxxx.xx>", "\n"; print $socket "DATA", "\n"; print $socket "xxxxxxxxxxxxxxxxx", "\n"; print $socket ".", "\n"; print $socket "QUIT", "\n";


if i print the responses from server i got a message says:

451 See http://pobox.com/~djb/docs/smtplf.html.

from "MAIL FROM:", "RCPT TO:", and "DATA" commands i get ok messages (DATA says "go ahead").

I went at that url (http://pobox.com/~djb/docs/smtplf.html) and i read about a problem with linefeed.

According to RFC 821 (SMTP rfc) when sending data at the end need a <CRLF> (on perl \r\n). I try the code with \r\n but the same message appear.


Anyone can help me ?

Thanks guys....
....and sorry for my "english"

Replies are listed 'Best First'.
Re: ESMTP, linefeed and <CRLF>
by fokat (Deacon) on Jul 26, 2002 at 01:32 UTC
    Well, first of all, before the MAIL FROM, you need to say something like

    HELO hostname
    This is the proper way to start the SMTP conversation.

    I tried with sendmail as the mail server and got your script to work (after adding the HELO) either with \n or with \r\n.

    Note also that you should fit your email message with some minimal headers to make it compliant with the RFC-822 syntax, and insure that your @'s are kept that way by escaping them. The code below does this:

    #!/usr/bin/perl use IO::Socket; $socket=IO::Socket::INET->new(PeerAddr => "mail.your.net", PeerPort => "25", Proto => "tcp" ) or die "MAIL: $!"; print $socket "HELO your_hostname\r\n"; print $socket "MAIL FROM: <you\@your.domain>\r\n"; print $socket "RCPT TO: <them\@their.domain>\r\n"; print $socket "DATA\r\n"; print $socket "From: <you\@your.domain>\r\n"; print $socket "To: <them\@their.domain>\r\n"; print $socket "Subject: My automatic message\r\n"; print $socket "\r\n"; print $socket "Your data here\r\n"; print $socket ".", "\r\n"; print $socket "QUIT", "\r\n";
    Finally, note that you're not really performing an SMTP dialog with the server, as mandated by the protocol. You're simply saying your part alone and as fast as you can. There is no error checking at all. This makes this approach unreliable.

    In order to properly handle potential problems with the message, you could read a line after you write each part. An easy way to do this could be:

    #!/usr/bin/perl use IO::Socket; $socket=IO::Socket::INET->new(PeerAddr => "mail.your.net", PeerPort => "25", Proto => "tcp" ) or die "MAIL: $!"; my $line = 'No line'; die "Error in greeting: $line" unless ($line = scalar <$socket>) =~ /^2/; print $socket "HELO your_hostname\r\n"; die "Error in HELO: $line" unless ($line = scalar <$socket>) =~ /^2/; print $socket "MAIL FROM: <you\@your.domain>\r\n"; die "Error in MAIL FROM: $line" unless ($line = scalar <$socket>) =~ /^2/; print $socket "RCPT TO: <them\@their.domain>\r\n"; die "Error in RCPT TO: $line" unless ($line = scalar <$socket>) =~ /^2/; print $socket "DATA\r\n"; die "Error in DATA: $line" unless ($line = scalar <$socket>) =~ /^3/; print $socket "From: <you\@your.domain>\r\n"; print $socket "To: <them\@their.domain>\r\n"; print $socket "Subject: My automatic message\r\n"; print $socket "\r\n"; print $socket "Your data here\r\n"; print $socket ".", "\r\n"; die "Error in DOT: $line" unless ($line = scalar <$socket>) =~ /^2/; print $socket "QUIT", "\r\n"; die "Error in QUIT: $line" unless ($line = scalar <$socket>) =~ /^2/;
    Which is not complete code, but would give you a good idea about how to move forward. Keep in mind that this example does not handle hairy cases such as multi-line greetings, which you can find in the real world.

    For a more complete solution, I would seek to use CPAN modules such as the ones my felow monks have suggested. It is often wise to challenge the restrictions in favor of not reinventing the wheel and using code that has been well tested and widely used by other people.

    Regards.

      You are right about HELO command and the error handling. I tried to keep code simple until it worked fine.

      I tried the way 'grep' monk said and it worked fine.

      Thank's for you tips !
Re: ESMTP, linefeed and <CRLF>
by grep (Monsignor) on Jul 25, 2002 at 22:51 UTC
    You might want to go to a higher level module Net::SMTP which has this all worked out already. This module comes standard with libnet

    You can see the example code is much cleaner and smaller

    #!/usr/local/bin/perl -w use Net::SMTP; $smtp = Net::SMTP->new('mailhost'); $smtp->mail($ENV{USER}); $smtp->to('postmaster'); $smtp->data(); $smtp->datasend("To: postmaster\n"); $smtp->datasend("\n"); $smtp->datasend("A simple test message\n"); $smtp->dataend(); $smtp->quit;
    Update: you can Install modules into your home directory

    grep
    Just me, the boy and these two monks, no questions asked.
      I tried your way and it worked fine.

      But i'm still wondering what this SMTP <crlf> error is?

      Thank's for your help !
Re: ESMTP, linefeed and <CRLF>
by december (Pilgrim) on Jul 26, 2002 at 02:31 UTC

    This might seem a bit of a work-around, but can't you send it through a pipe on the localhost? The local mta interface ofcourse won't have any problems with converting this (seems qmail, so the fake sendmail binary or qmail-inject).

    Something like (uh... I leave the conversion to perl as exercise ;) ):

    #!/bin/sh ( echo "From: you@example.com" echo "To: smb@example.net" echo -e "Subject: info\n" cat <<__EOF__ hmmz __EOF__ ) | /usr/sbin/sendmail smb@example.net

    Good luck,

       wouter

      This is a thing that i haven't think. It's a nice way to send mail but i prefer the Net::SMTP way "grep" monk said.

      Thank's wouter
Re: ESMTP, linefeed and <CRLF>
by IlyaM (Parson) on Jul 26, 2002 at 06:45 UTC
    I'm trying to make a script that it will get data from submit of some forms and send the data to a specific mail account. On the machine that the script will run i cannot add modules so i must use IO::Socket.

    Sounds like formmail. May be you can use it or at least steal code from it.

    --
    Ilya Martynov (http://martynov.org/)

      I saw the code of formmail and i think it is too much for that i want.

      I don't think that steeling code for me that i'm new to Perl will help.

      Thank's for you help Ilya !