Net::SMTP freezes on a certain server - perl

I have a Perl script for sending Emails:
#!/usr/bin/perl
use strict;
use warnings;
use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTP ();
use Email::Simple ();
use Email::Simple::Creator ();
my $smtpserver = 'server.com';
my $smtpport = 2525;
my $smtpuser = 'test#server.com';
my $smtppassword = 'secret';
my $transport = Email::Sender::Transport::SMTP->new({
host => $smtpserver,
port => $smtpport,
sasl_username => $smtpuser,
sasl_password => $smtppassword,
debug => 1,
});
my $email = Email::Simple->create(
header => [
To => 'myself#gmail.com',
From => "User name <$smtpuser>",
Subject => 'Hello',
],
body => "This is my message\n",
);
sendmail($email, { transport => $transport });
It works on one server. But on another the script freezes. Debug messages are:
Net::SMTP>>> Net::SMTP(2.31)
Net::SMTP>>> Net::Cmd(2.29)
Net::SMTP>>> Exporter(5.63)
Net::SMTP>>> IO::Socket::INET(1.31)
Net::SMTP>>> IO::Socket(1.31)
Net::SMTP>>> IO::Handle(1.28)
What's wrong? How to debug?

This happens if the TCP connection to the server was successfully established but the server does not send the expected SMTP greeting back. This can have several reasons, like:
The server is not a SMTP server at all. If you try to use Net::SMTP against a web server (e.g. HTTP) you will see a similar result, because the HTTP server expects the client to send data first whereas with SMTP the server will send data first.
The server has implicit TLS configured, that is it is waiting for the client to connect with TLS and not with plain SMTP. In this case the server is waiting for the client to start with the TLS handshake (i.e send ClientHello) before sending anything back.
I would suggest you look at the configuration of the server to see what is actually is expected.

Related

Unable to submit email on port 465 using Net::SMTP module in Perl

I want to submit email on port 465 of my smtp server using the Net::SMTP module(without using Net::SMTP::SSL) in a perl script from client. On Port 465 of my SMTP server, "submissions" service runs, which understands SMTPS.
I have tried to find the way to do this on google. Then used the Net::SMTP::SSL module to make request on port 465. It works fine.
But the documentation for Net::SMTP::SSL recommends using latest version Net::SMTP instead of using Net::SMTP::SSL.
The document clearly states that
Since Net::SMTP v1.28 (2014-10-08), Net::SMTP itself has support for
SMTP over SSL, and also for STARTTLS. Use Net::SMTP, not
Net::SMTP::SSL.
I have updated Net::SMTP module to the latest version 3.11.
Also the document for Net::SMTP also stated clearly that
With IO::Socket::SSL installed it also provides support for implicit
and explicit TLS encryption, i.e. SMTPS or SMTP+STARTTLS.
The part of my perl script code on client ,relevant to the problem mentioned looks like so:
$smtp = Net::SMTP::SSL->new("$mailserver",
Hello => "$localhostname",
Timeout => 60,
Port => "$port", //Port value is 465
Debug => 1);
$smtp->auth($username, $password);
...Remaining script which sets sender, receiver body etc
This works fine. The email gets submitted.
Replacing the above code with :
$smtp = Net::SMTP->new("$mailserver",
Hello => "$localhostname",
Timeout => 60,
Port => "$port", //Port value is 465
Debug => 1);
$smtp->auth($username, $password);
...Remaining script which sets sender, receiver body etc
This fails. The debug logs look like this:
Net::SMTP>>> Net::SMTP(3.11)
Net::SMTP>>> Net::Cmd(3.11)
Net::SMTP>>> Exporter(5.73)
Net::SMTP>>> IO::Socket::INET(1.39)
Net::SMTP>>> IO::Socket(1.39)
Net::SMTP>>> IO::Handle(1.39)
Net::SMTP: Net::Cmd::getline(): unexpected EOF on command channel: at fescommon/mailsend-new.pl line 67.
Can't call method "auth" on an undefined value at fescommon/mailsend-new.pl line 74.
Note: Modules like Net::SMTP, Net::SMTP::SSL, IO::Socket::SSL and others are all updated to the latest version.
Expected Result is that request on "submissions" service listening on port 465 on SMTP server can be made using latest Net::SMTP module, without using Net::SMTP::SSL (because the document claims)
If you want to use smtps (i.e. TLS from start instead TLS after the STARTTLS command) you have to explicitly say so. Net::SMTP does not magically derive this requirement from the port number. From the documentation:
new ( [ HOST ] [, OPTIONS ] )
SSL - If the connection should be done from start with SSL, contrary to later upgrade with starttls. You can use SSL arguments as documented in IO::Socket::SSL, but it will usually use the right arguments already.
Thus, the proper code should be:
$smtp = Net::SMTP->new($mailserver,
SSL => 1, # <<<<<<<<<<<<<<<<<<<<<<<< THIS IS IMPORTANT
Hello => $localhostname,
Timeout => 60,
Port => $port, # Port value is 465
Debug => 1
);

IO::Socket::SSL - establishing client connection

As per the documentation of IO::Socket::SSL (PERL) I understand that if I want to just send command to specific server-program that running on port 9999 on my host, Ican do it this way:
my $cl=IO::Socket::SSL->new("localhost:9999"); # locallost is my real case, anyway
if($cl) {
$cl->connect_SSL or die $#;
# Something about certificates?
$cl->syswrite("Command");
close($cl);
}
But the error I get is: "SSL connect attempt failed with unknown error error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol at blabla.cgi line 888"
The server initialized thi way (in another pl program):
use IO::Socket::SSL;
use Net::WebSocket::Server;
my $CON={};
my #crt=&SSLCerts(); die 'E101' if(#crt==0);
my $ssl=IO::Socket::SSL->new(
Listen => 10000,
Timeout => 45,
LocalPort => 9999,
Proto => 'tcp',
SSL_cert_file => "$EF::Base/ssl/certs/$crt[0][0].crt",
SSL_key_file => "$EF::Base/ssl/keys/$crt[1][0].key"
) or die "E102: $!";
Net::WebSocket::Server->new(
listen => $ssl,
silence_max=> 3600,
tick_period => 5,
on_tick => sub {
# Empty for now
},
on_connect => sub {
my($serv,$conn)=#_; my($cid,$sid);
$conn->on(
handshake => sub {
my($cnc,$hdk)=#_;
my $nsn=$hdk->req->resource_name;
$cid=substr($nsn,4,index($nsn,'&L=')-4);
$CON->{$cid}=$cnc; # Register incomming connection
},
binary => sub {
# Handle incomming message from the client
},
disconnect => sub {
delete $CON->{$cid};
}
);
}
)->start;
Typical Websocket client that is connecting from the browser via "wss://" connects without any trouble.... The server MUST be SSL...
Here I am just trying to do the same from within perl.
What I am doing wrong? Nothing mentioned about certificates in client, only in server - the server is working fine. Maybe configuration? I have purchased SSL certificates and I use them for the server that running ok on that port.
The host is Linux (CentOS - if it matters).
... SSL23_GET_SERVER_HELLO:unknown protocol
This is the kind of error you get if the client tries to do a SSL handshake and the server responds with something which is not SSL. Typically this happens if you connect to a server which is not (properly) SSL enabled (at least not on this port) or requires some plain text to upgrade to SSL (like in case of SMTP STARTTLS and similar).
This kind of error has usually nothing to do with certificates.
This kind of error can only happen if you try to do an SSL handshake on an already established SSL socket but the server does not expect this. This seems to happen in your case:
my $cl=IO::Socket::SSL->new("localhost:9999"); # locallost is my real case, anyway
if($cl) {
$cl->connect_SSL or die $#;
...
The SSL connection is already being established by IO::Socket::SSL->new. This is the same with IO::Socket::INET or similar: if the target is given it will already connect inside new and an additional connect or connect_SSL should not be done. This is also reflected in the documentation and examples.
Since version 2.045 (released 02/2017) IO::Socket::SSL will simply ignore a connect_SSL if the SSL handshake is already done. You are likely using an older version of IO::Socket::SSL where connect_SSL will start a new handshake even if the TLS handshake was already finished. This handshake inside the TLS connection will result in the strange error you see.

SMTP Authentication problem

I'm writing a simple mail client in Perl, that uses SMTP to log in a Mail server, and from there sends a mail to another E-mail address (on different host). I use raw SMTP commands, because strawberry perl doesn't come with SASL.pm which is needed in order to authenticate. However, when the script tries to authenticate itself, it fails. I tried 'AUTH LOGIN' and 'AUTH PLAIN' mechanism but no luck. Here is an example:
EHLO example.com
AUTH LOGIN
YWxwaGE=
cGFzc3dvcmQ=
MAIL FROM:<alpha#example.com>
RCPT TO:<beta#betadomain.com>
DATA
Subject: sample message
From: alpha#example.com
To: beta#betadomain.com
Greetings,
Typed message (content)
Goodbye.
.
QUIT
EOT
"YWxwaGE=", "cGFzc3dvcmQ=" are the user and password encoded in Base64. Whatever I submit the server always complains that either the username or the password is wrong. What do I do wrong?
Why not just install a module that supports SMTP with SASL? One of the advantages of Strawberry Perl is that you can easily install modules from CPAN.
For example, Email::Simple and Email::Sender:
use strict;
use warnings;
use Email::Sender::Simple qw(sendmail);
use Email::Simple;
use Email::Simple::Creator;
use Email::Sender::Transport::SMTP;
my $email = Email::Simple->create(
header => [
To => 'beta#betadomain.com',
From => 'alpha#example.com',
Subject => "sample message",
],
body => "Greetings,\nTyped message (content)\nGoodbye.\n",
);
my $transport = Email::Sender::Transport::SMTP->new({
host => 'smtp.example.com',
sasl_username => 'foo',
sasl_password => 'bar',
});
sendmail($email, { transport => $transport });

How can I send mail to Gmail with an attachment, in Perl?

How can I send mail to Gmail using Perl? Here's what I'm trying:
my $mailer = Email::Send->new(
{
mailer => 'SMTP::TLS',
mailer_args => [
Host => 'smtp.gmail.com',
Port => 587,
User => 'xxx',
Password => 'xxx',
]
}
);
use Email::Simple::Creator; # or other Email::
use File::Slurp;
#arrIrc = read_file("$ircFile");
my $email = Email::Simple->create(
header => [
From => 'xxx',
To => "$configList{email}",
Subject => "The summary of logfile $channelName",
],
body => "#arrIrc",
);
Use Net::SMTP::SSL to talk to GMail.
See MIME::Lite inline images on Perlmonks for an example.
If you want to send mail to Gmail, you do the same thing you would do to send mail anywhere. If you want to send mail through Gmail, there is the Email::Send::Gmail module. Merely typing your question in Google led me to Sending Mail Through Gmail with Perl by Mark Sanborn.
You can use MIME::Lite to compose a message, which you then send to your local sendmail process. However, in order to talk to gmail's servers you need to have SSL certificates set up. There's probably more detailed instructions for that on superuser.

How do I send email to my Gmail account using SMTP and Perl?

I don't want to use sendmail to send an email but would prefer to use SMTP. How can I use Perl to send an email to my GMAIL account?
personally I would suggest you to use my module Email::Send::SMTP::TLS
which works pretty well through the TLS of Google Mail.
Thanks.
use Email::Send;
my $mailer = Email::Send->new( {
mailer => 'SMTP::TLS',
mailer_args => [
Host => 'smtp.gmail.com',
Port => 587,
User => 'username#gmail.com',
Password => 'password',
Hello => 'fayland.org',
]
} );
use Email::Simple::Creator; # or other Email::
my $email = Email::Simple->create(
header => [
From => 'username#gmail.com',
To => 'to#mail.com',
Subject => 'Subject title',
],
body => 'Content.',
);
eval { $mailer->send($email) };
die "Error sending email: $#" if $#;
As per the comment, it's not clear if you want to send email via Google's SMTP, or just send email in general (perhaps to your gmail account). You should check out Email::Send and possibly Email::Send::Gmail.
Alternatively, if what you're really asking is how do I move email from somewhere that isn't Gmail to Gmail, I've had very good luck with IMAP using Mail::Box and the Mail::Box::IMAP4::SSL backend. You can see an example of use here.
I've always used and had very good luck with Mail::Sender.
Another possibility you might want to look at is using the Email::Send::Gmail module from CPAN. This will allow you to send email from your Gmail account to any account (for example, to yourself)
There are muliple SMTP modules on CPAN, for example Net::ESMTP. Also, sendmail very probably does use SMTP to communicate with mail servers, so what's your real reason for not wanting to use it?
Email::Send (as used in Fayland Lam's answer) is deprecated:
Email::Send is going away... well, not really going away, but it's
being officially marked "out of favor."
This works for me, using the preferred Email::Sender:
use strict;
use warnings;
use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTPS ();
use Email::Simple ();
use Email::Simple::Creator ();
my $smtpserver = 'server';
my $smtpport = 587;
my $smtpuser = 'username';
my $smtppassword = 'password';
my $transport = Email::Sender::Transport::SMTPS->new({
host => $smtpserver,
port => $smtpport,
ssl => "starttls",
sasl_username => $smtpuser,
sasl_password => $smtppassword,
});
my $email = Email::Simple->create(
header => [
To => 'mymail#gmail.com',
From => 'sender#example.com',
Subject => 'Hi!',
],
body => "This is my message\n",
);
sendmail($email, { transport => $transport });
If you aren't familiar with CPAN (Comprehensive Perl Archive Network) I recommend you to bookmark that site. It contains third party (mostly well tested) libraries.
An example showing how to send emails using perl: http://www.perlfect.com/articles/sendmail.shtml
I happen to use MIME::Lite, which is a wrapper around Net::SMTP to simplify the process of building email objects, file attachments, and sending the payload.
If you're not familiar with installing modules, check:
On Windows, use the ActiveState Perl Package Manager (in start menu)
On Unix, use CPAN: $ sudo cpan Module::Name
On hosted Unix accounts: How can I install a CPAN module into a local directory?
If you just don't like sendmail, another option is to use Postfix, another MTA.
Here are the instructions I followed to get it setup on my machine, using gmail:
http://souptonuts.sourceforge.net/postfix_tutorial.html
This might be useful too, if you get a warning about failing to verify a certificate from Thawte Premium Server CA.
http://ubuntuforums.org/archive/index.php/t-894355.html