Search code examples
perlemailmime

How to check if last email sent was successfully delivered or not using MIME::Lite perl


I wanted to send emails in perl code. So I used MIME::Lite module.

I am able to send emails as I wanted if I removed last_send_successful check, else I get error mentioned below.I want to know if the email was sent successfully. Below is the code snippet I used.

sub sendEmailWithCSVAttachments {
    my $retries        = 3;
    my $retry_duration = 500000;    # in microseconds
    my $return_status;
    my ( $from, $to, $cc, $subject, $body, @attachments_path_array );

    $from                   = shift;
    $to                     = shift;
    $cc                     = shift;
    $subject                = shift;
    $body                   = shift;
    @attachments_path_array = shift;

    my $msg = MIME::Lite->new(
        From    => $from,
        To      => $to,
        Cc      => $cc,
        Subject => $subject,
        Type    => 'multipart/mixed'
    ) or die "Error while creating multipart container for email: $!\n";

    $msg->attach(
        Type => 'text',
        Data => $body
    ) or die "Error while adding text message part to email: $!\n";

    foreach my $file_path (@attachments_path_array) {

        my $file_name = basename($file_path);
        $msg->attach(
            Type        => 'text/csv',
            Path        => $file_path,
            Filename    => $file_name,
            Disposition => 'attachment'
        ) or die "Error while adding attachment $file_name to email: $!\n";
    }

    my $sent = 0;
    while ( !$sent && $retries-- > 0 ) {

        eval { $msg->send(); };

        if ( !$@ && $msg->last_send_successful() ) {
            $sent = 1;
        } else {
            print "Sending failed to $to.";
            print "Will retry after $retry_duration microseconds.";
            print "Number of retries remaining $retries";
            usleep($retry_duration);
            print "Retrying...";
        }
    }

    if ($sent) {
        my $sent_message = $msg->as_string();
        print "Email sent successfully:";
        print "$sent_message\n";
        $return_status = 'success';
    } else {
        print "Email sending failed: $@";
        $return_status = 'failure';
    }
}

The error I am getting is:

Can't locate object method "last_send_successful" via package "MIME::Lite"

This means this method is not present. But it is given in the reference I am using.

  1. So am I missing something or is there alternative to check if the last send was successful or the reference I am using is incorrect?

  2. Is this check redundant as I am already using eval block?

  3. Will using eval catch the error of email not getting delivered? (Most probably no but want to confirm)

  4. How to make sure that email is delivered with MIME::Lite?


Solution

  • You don't need to use the eval block or do anything fancy to ensure that the mail has been sent; that is what last_send_successful is for. When the send subroutine successfully completes its work, it sets an internal variable ($object->{last_send_successful}); this is what the last_send_successful sub is checking. It is usually not necessary to use an eval block unless you are trying to prevent a script dying or throwing a runtime or syntax error.

    You can simplify your code to something like the following:

    $msg->send;
    
    if ($msg->last_send_successful) {
        # woohoo! Message sent
    }
    else {
        # message did not send.
        # take appropriate action
    }
    

    or

    $msg->send;
    
    while (! $msg->last_send_successful) {
        # message did not send.
        # take appropriate action
    }