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

Dear monks,

I'm attempting to get a form mailer running (the MTA has already been set up and is running smoothly), but for some reason the MTA refuses to accept the connection. Normally when attempting to send a mail from one of the mailboxes, it responds immediately, and the mail in question is delivered (problems would normally occur at the remote end). However, when attempting to send something via the form mailer, things are met with failure.

I have set a null address as a sender for the mailer (it is present in /etc/aliases and I have run newaliases so that cannot be an issue), my mail address as a recipient, and I'm also plugging in the mail address given in the form field both as Cc (if copy has been selected by the submitter) and the Reply-To field.

The following code is in use here: Wrapper function to avoid the same rigmarole at different spots

package sendmail; require Exporter; use strict; use Net::SMTP; use IO::Socket::SSL; use checktld; use Net::DNS::Resolver; our @ISA = qw(Exporter); our @EXPORT_OK = qw(send_mail); our $debug = 0; sub validate_mailaddr { my $p_email_addr = $_[0]; my $l_valid_format; my $l_dns_error; die "validate_mailaddr: Illegal argument count" if(@_ != 1); my $l_dns = Net::DNS::Resolver->new( nameservers => [ qw(127.0.0.1) +] ); $p_email_addr =~ /^([^\s@,:"<>]+)@([^\s@,:"<>]+)\.([^\s@,:"<>.\d]{2, +})$/; return undef if(!valid_tld($3)); $l_dns->query($2.'.'.$3); $l_dns_error = $l_dns->errorstring; return undef if($l_dns_error eq 'NXDOMAIN'); return undef if($l_dns_error ne 'NOERROR'); return "$1\@$2.$3"; }; sub send_mail { my $p_sender; my $p_recipient; my $p_response_path; my $p_cc; my $p_subject; my $p_message; my $l_result = 1; my $l_mailer; my $l_status; my $l_eval_err; die "send_mail: Illegal argument count" if(@_ != 6); ($p_sender,$p_recipient,$p_response_path,$p_cc,$p_subject,$p_message +) = @_; print STDERR "Sanity check of recipient address...\n" if($p_debug); return 0 if(!defined ($p_recipient = validate_mailaddr($p_recipient) +)); print STDERR "Sanity check of response path address...\n" if($p_debu +g && $p_response_path ne ''); if($p_response_path ne '') { return 0 if(!defined ($p_response_path = validate_mailaddr($p_resp +onse_path))); } print STDERR "$p_recipient\n" if($debug); $l_mailer = Net::SMTP->new( 'localhost', Hello => '<insert domain name here>', Timeout => 60, SSL => 1 ); return undef if(!defined $l_mailer); $l_status = eval { print STDERR "Sending MAIL FROM...\n" if($debug); $l_mailer->mail($p_sender); print STDERR "Attempting RCPT TO...\n" if($debug); if($l_mailer->to($p_recipient)) { print STDERR "Sending CC...\n" if($p_cc && $debug); $l_mailer->cc($p_response_path) if($p_cc && $p_response_path ne +''); print STDERR "Sending message data...\n"; $l_mailer->data(); $l_mailer->datasend("Content-Type: text/plain; charset=utf-8\n") +; $l_mailer->datasend("From: <$p_sender>\n"); $l_mailer->datasend("To: <$p_recipient>\n"); $l_mailer->datasend("Reply-To: <$p_response_path>\n") if($p_resp +onse_path $l_mailer->datasend("Cc: <$p_response_path>\n") if($p_response_p +ath && $p $l_mailer->datasend("Subject: $p_subject\n\n"); $l_mailer->datasend("$p_message"); $l_mailer->dataend(); return "OK"; } else { return "Connection refused"; } }; $l_eval_err = $@; $l_mailer->quit; if($l_eval_err) { $l_result = 0; print STDERR "The transaction failed: $@\n"; $l_result = -1 if($l_eval_err =~ /Greylisted/); } if($l_status ne 'OK') { print STDERR "The transaction failed: $l_status\n"; return 0; } return $l_result; }; 1; __END__

The TLD check function is defined here (normally the module is auto-generated every now and then to accommodate for possible TLD changes) - this function is called in a plausibility check of the mail addresses:

package checktld; require Exporter; use strict; our @ISA = qw(Exporter); our @EXPORT = qw(valid_tld); my @tldlist = ( <insert some tlds here for testing purposes> ); sub valid_tld { my $p_this = $_[0]; return undef if(@_ != 1); foreach (@tldlist) { return 1 if($p_this eq $_); } return 0; }; 1; __END__

This is my test case:

#!/usr/bin/perl -wT -I /srv/www1-ssl/cgi-lib use strict; use sendmail qw(send_mail); $sendmail::debug = 1; my $sender = '<insert sender address here>'; my $destination = '<insert recipient address here>'; my $headline = 'Test'; my $msg = 'This is a test message.'; my $result = send_mail($sender, $destination, '', 0, $headline, $msg); if($result == 1) { print "Message sent\n"; } elsif($result == -1) { print "Message transmission temporarily blocked\n"; } else { print "Transmission failure\n"; } __END__

This is the output of a test run:

Sanity check of recipient address... <recipient address seen here> Sending MAIL FROM... Attempting RCPT TO... The transaction failed: Connection refused Transmission failure

For some reason the ATM detects an error in the transmission sequence and blocks the connection for 30 seconds (a security feature). Now I'm wondering what is going wrong here. FYI, this problem cropped up after upgrading to openSuSE Leap 42.2 - under openSuSE 13.2 things were actually running smoothly...

Thanks for your help.

Replies are listed 'Best First'.
Re: Net::SMTP - Connection to local MTA refused
by noxxi (Pilgrim) on Mar 07, 2017 at 05:22 UTC
    It is unknown what kind of setup you really have but "Connection refused" is usually caused either by a firewall blocking connections (unlikely with localhost) or that simply no server is listening there.
    Based on your use of Net::SMTP connection should work if you have a MTA setup on localhost port 465 (smtps), speaking directly TLS (i.e. no upgrade with STARTTLS) and with a valid certificate for "localhost". I have no idea if this is really the case but I would guess it is not.
    To better debug the problem I would recommend to use the "Debug" switch for Net::SMTP. For SSL debugging run your code with "perl -MIO::Socket::SSL=debug4 program.pl".

      The point is that the connection attempt does show up in the logs, but beyond the connection being initiated, nothing more happens. I'm experiencing the same issues when I set SSL => 0 (this is still possible, because my MTA is configured so that TLS doesn't have to be used for incoming mails) so it's not a problem with SSL/TLS, though. As far as the form mailer is concerned, it is supposed to transmit its data on port 25. No idea why it stopped working after upgrading the distro...

      However, I'm going to give the Debug approach a shot.

      EDIT: It appears that STARTTLS is required, but the method starttls() seems to be missing in my Net::SMTP...

      Anyway, here's what the script dumped with Debug enabled:

      Sanity check of recipient address... <recipient address displayed here> Net::SMTP>>> Net::SMTP(2.31) Net::SMTP>>> Net::Cmd(2.29) Net::SMTP>>> Exporter(5.68) Net::SMTP>>> IO::Socket::INET(1.33) Net::SMTP>>> IO::Socket(1.36) Net::SMTP>>> IO::Handle(1.34) Net::SMTP=GLOB(0x1c9d748)<<< 220 <domain name displayed here> mail. Al +l spam is reported. ESMTP Net::SMTP=GLOB(0x1c9d748)>>> EHLO <domain displayed here> Net::SMTP=GLOB(0x1c9d748)<<< 250-<server name displayed here> Net::SMTP=GLOB(0x1c9d748)<<< 250-PIPELINING Net::SMTP=GLOB(0x1c9d748)<<< 250-SIZE 26214400 Net::SMTP=GLOB(0x1c9d748)<<< 250-ETRN Net::SMTP=GLOB(0x1c9d748)<<< 250-STARTTLS Net::SMTP=GLOB(0x1c9d748)<<< 250-ENHANCEDSTATUSCODES Net::SMTP=GLOB(0x1c9d748)<<< 250-8BITMIME Net::SMTP=GLOB(0x1c9d748)<<< 250 DSN Issuing STARTTLS... Net::SMTP=GLOB(0x1c9d748)>>> QUIT Net::SMTP=GLOB(0x1c9d748)<<< 221 2.0.0 Bye The transaction failed: Can't locate object method "starttls" via pack +age "Net::SMTP" at /srv/www1-ssl/cgi-lib/sendmail.pm line 74. Transmission failure

      UPDATE: I had to update both Net::SMTP and IO::Socket::SSL from CPAN. After the update STARTTLS could be issued, but that caused another bunch of problems to appear:

      Sanity check of recipient address... <recipient address shown here> Net::SMTP>>> Net::SMTP(3.10) Net::SMTP>>> Net::Cmd(3.10) Net::SMTP>>> Exporter(5.68) Net::SMTP>>> IO::Socket::IP(0.37) Net::SMTP>>> IO::Socket(1.36) Net::SMTP>>> IO::Handle(1.34) Net::SMTP=GLOB(0x20461c8)<<< 220 <domain shown here> mail. All spam is + reported. ESMTP Net::SMTP=GLOB(0x20461c8)>>> EHLO <domain shown here> Net::SMTP=GLOB(0x20461c8)<<< 250-<server address shown here> Net::SMTP=GLOB(0x20461c8)<<< 250-PIPELINING Net::SMTP=GLOB(0x20461c8)<<< 250-SIZE 26214400 Net::SMTP=GLOB(0x20461c8)<<< 250-ETRN Net::SMTP=GLOB(0x20461c8)<<< 250-STARTTLS Net::SMTP=GLOB(0x20461c8)<<< 250-ENHANCEDSTATUSCODES Net::SMTP=GLOB(0x20461c8)<<< 250-8BITMIME Net::SMTP=GLOB(0x20461c8)<<< 250 DSN Issuing STARTTLS... Net::SMTP=GLOB(0x20461c8)>>> STARTTLS Net::SMTP=GLOB(0x20461c8)<<< 220 2.0.0 Ready to start TLS Sending MAIL FROM... Net::SMTP=GLOB(0x20461c8)>>> MAIL FROM:<sender address shown here> Net::SMTP: Net::Cmd::getline(): unexpected EOF on command channel: at + /srv/www1-ssl/cgi-lib/sendmail.pm line 76. Attempting RCPT TO... Net::SMTP: Net::Cmd::_is_closed(): unexpected EOF on command channel: + at /srv/www1-ssl/cgi-lib/sendmail.pm line 78. Net::SMTP: Net::Cmd::_is_closed(): unexpected EOF on command channel: + at /srv/www1-ssl/cgi-lib/sendmail.pm line 78. Net::SMTP: Net::Cmd::_is_closed(): unexpected EOF on command channel: + at /srv/www1-ssl/cgi-lib/sendmail.pm line 102. Net::SMTP: Net::Cmd::_is_closed(): unexpected EOF on command channel: + at /srv/www1-ssl/cgi-lib/sendmail.pm line 102. The transaction failed: Connection refused Transmission failure
        It appears the MTA is closing the connection right after you send the "MAIL FROM:" string.
        Net::SMTP=GLOB(0x20461c8)>>> MAIL FROM:<sender address shown here>
        Net::SMTP: Net::Cmd::getline(): unexpected EOF on command channel:  at
        + /srv/www1-ssl/cgi-lib/sendmail.pm line 76.
        

        So, it's either the MTA itself, or some external thing like AppArmor (enabled by default in the OpenSuse version you mention).

        I would look at the logs for whatever your MTA is (exim maybe?) as well as AppArmor, SELinux, or whatever other external security stuff you may have running.

        Maybe also try "service boot.apparmor stop", and see if turning off AppArmor makes a difference. Not the right solution, but quick to try.

        ok, i may be missing something here, but dont modern mail senders require you to authenticate first? ie:

        $l_mailer->auth($smtpuser, $smtppassword);
        before
        $l_mailer->mail($p_sender);