perlsmtpdancer

Debugging Email::Sender::Simple with Email::Sender::Transport::SMTPS


I'm writing an email service which sends data to my users with Email::Sender::Simple and Email::Sender::Transport::SMTPS. Right now, I've got a package which should just take some inputs and send an e-mail:

package MyApp::Service::Mail;

use Email::Sender::Simple qw(sendmail);
use Email::Simple;
use Email::Sender::Transport::SMTPS;
use Try::Tiny;
use Dancer;

use constant CANT_SEND_MAIL    => -1;
use constant SENT_SUCCESSFULLY => 1;

sub new {
    my $class   = shift;
    my $self    = {};

    bless  $self, $class;
    return $self;
}

sub sendEmail {
    my $self    = shift;
    my $to      = shift;
    my $subject = shift;
    my $body    = shift;
    my $failed  = 0;

    my $email = Email::Simple->create(
        header => [
            To      => $to,
            From    => 'noreply@myapp.com',
            Subject => $subject
        ],
        body => $body
    );

    my $transport = Email::Sender::Transport::SMTPS->new({
        host          => config->{smtp_host},
        port          => config->{smtp_port},
        sasl_username => config->{smtp_username},
        sasl_password => config->{smtp_password},
        ssl           => 'ssl'
    });

    try {
        sendmail($email, {transport => $transport});
    } catch {
        $failed = 1;
    }

    return $self->CANT_SEND_MAIL if ($failed eq 1);
    return $self->SENT_SUCCESSFULLY;
}

1;

This is based heavily on the example from the CPAN page for the modules involved.

Note that those config variables are coming from Dancers config.yml, and I have confirmed they are being passed in correctly. I have also confirmed that $to, $body and $subject contain what I expect them to.

The sendEmail function is being called and returning 1 (SENT_SUCCESSFULLY) but I cannot see anything in the Sent box on my e-mail client, and there is nothing at the receiving address either. I've been trying to find some kind of debug function to delve deeper into why this is failing, but to no avail.

Code calling this is:

package MyApp::Service::Mail::User;

use MyApp::Service::Mail;
our @ISA = qw(MyApp::Service::Mail);

sub sendPasswordByEmail {
    my $self     = shift;
    my $to       = shift;
    my $username = shift;

    my $subject = "Test E-Mail";

    (my $body = << "    END_MESSAGE") =~ s/^ {4}//gm;
    Dear $username,

    This is a test e-mail.
    END_MESSAGE

    return $self->sendEmail($to, $subject, $body);
}

1;

I can confirm the SMTP account definitely works as I use it in my e-mail client (Thunderbird). Any suggestions as to why this function could be returning 1 with no success? Is there a way to debug the connection between this and my SMTP server (it's 3rd party so can't check the logs) to see if a connection is being established and what's being passed / whether there's a problem?


Solution

  • There is a semicolon missing after the try {} catch {} block. Without it, the following line becomes part of the same statement, so the entire try/catch block is conditional based on $failed, which will never be 1 at that point.

    This is an unfortunate side effect of the implementation of Try::Tiny, but it can't be avoided in a pure-perl implementation. Your existing code is parsed is like:

    try(
        sub {
            sendmail($email, {transport => $transport});
        },
        catch(
            sub {
                $failed = 1;
            },
            return($self->CANT_SEND_MAIL),
        ),
    ) if ($failed eq 1);