I have been upgrading some Perl sendmail automated emails to take advantage of features with Email::MIME::CreateHTML and Email::Sender notably SMTP authentication. It works fine.
use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTP ();
use Email::MIME::CreateHTML;
my $smtpserver = 'myserver.com';
my $smtpport = ###;
my $smtpuser = 'noreply#mywebsite.com';
my $smtppassword = 'mypassword';
my $xport = Email::Sender::Transport::SMTP->new({
host => $smtpserver,
port => $smtpport,
ssl => 'ssl',
sasl_username => $smtpuser,
sasl_password => $smtppassword,
});
my $email = Email::MIME->create_html(
header => [
To => $email_to_recipient,
From => $email_from_person,
Subject => $email_subject_line,
],
body => $email_body_code,
);
sendmail($email, { transport => $transport });
However, I have not been able to find anywhere in the documents how to add a Reply-to option. Using sendmail it was as simple as adding another line:
print SENDMAIL "From: noreply\#myserver.com\n";
print SENDMAIL "To: recipient#theirserver.com";
print SENDMAIL "Reply-to: replyhere#myserver.com\n";
Tried to sneak in:
my $email = Email::MIME->create_html(
header => [
To => $email_to_recipient,
From => $email_from_person,
Reply-to => $email_reply_to_person,
Subject => $email_subject_line,
],
body => $email_body_code,
);
sendmail($email, { transport => $transport });
but the reply-to part was ignored. Any help would be appreciated.
Related
I have adapted a script from the Perl Cookbook. I am testing it to send mail to myself in gmail.
#!/usr/bin/perl
use strict;
use warnings;
use MIME::Lite;
my $msg;
$msg = MIME::Lite->new(From => 'zmumba#gmail.com',
To => 'zmumba#gmail.com',
Subject => 'My office photo',
Type => 'multipart/mixed');
$msg->attach(Type => 'image/png',
Path => '/home/zmumba/ZMD_Proj/Docs/Reporting',
Filename => 'office_lyout.png');
$msg->attach(Type => 'TEXT',
Data => 'I hope you can use this!');
$msg->send( );
When I run this script, I get the message "/home/zmumba/ZMD_Proj/Docs/Reporting" not readable.
From here How can I send mail through Gmail with Perl? , I now understand that I have to send mail through a mailserver to use MIME::Lite. So I replaced
$msg = MIME::Lite->new(From => 'zmumba#gmail.com
with
$msg = Email::Send::Gmail->new(From => 'zmumba#gmail.com
and I get the error "Can't locate object method "new" via package Email::Send::Gmail".
Then I tried
$msg = Net::IMAP::Simple::SSL->new(From => 'zmumba#gmail.com',
and I get "Odd number of elements in hash assignment at /home/zmumba/perl5/lib/perl5/Net/IMAP/Simple.pm line 25.
Can't call method "attach" on an undefined value at ...".
Any assistance on how to go about it?
Thanks in anticipation.
The Perl Cookbook is 20 years old and its recommendations will be out of date. Using MIME::Lite is discouraged.
MIME::Lite is not recommended by its current maintainer. There are a number of alternatives, like Email::MIME or MIME::Entity and Email::Sender, which you should probably use instead. MIME::Lite continues to accrue weird bug reports, and it is not receiving a large amount of refactoring due to the availability of better alternatives. Please consider using something else.
You should probably follow their recommendation and use Email::Sender.
"Can't locate object method "new" via package Email::Send::Gmail"
You need to load Email::Send::Gmail with use Email::Send::Gmail.
You may need to install the Email::Send::Gmail module. It's simplest to do this using either cpanminus or install a fresh Perl with perlbrew and then use cpanminus.
Then I tried
$msg = Net::IMAP::Simple::SSL->new(From => 'zmumba#gmail.com',
and I get "Odd number of elements in hash assignment at /home/zmumba/perl5/lib/perl5/Net/IMAP/Simple.pm line 25.
MIME::Lite, Email::Send::Gmail, and Net::IMAP::Simple::SSL are different libraries with different interfaces that take different arguments differently. Refer to their documentation for how to use them.
As mentioned before, both MIME::Lite and Email::Send is discouraged -
Email::Send is going away... well, not really going away, but it's
being officially marked "out of favor." It has API design problems
that make it hard to usefully extend and rather than try to deprecate
features and slowly ease in a new interface, we've released
Email::Sender which fixes these problems and others
I have created a script which uses Email::MIME, Email::Sender::Simple, Email::Sender::Transport::SMTP for sending mail. You can take a look at https://github.com/rai-gaurav/perl-toolkit/tree/master/Mail and use it as per your requirement.
Important lines from that code are -
sub create_mail {
my ( $self, $file_attachments, $mail_subject, $mail_body ) = #_;
my #mail_attachments;
if (#$file_attachments) {
foreach my $attachment (#$file_attachments) {
my $single_attachment = Email::MIME->create(
attributes => {
filename => basename($attachment),
content_type => "application/json",
disposition => 'attachment',
encoding => 'base64',
name => basename($attachment)
},
body => io->file($attachment)->all
);
push( #mail_attachments, $single_attachment );
}
}
# Multipart message : It contains attachment as well as html body
my #parts = (
#mail_attachments,
Email::MIME->create(
attributes => {
content_type => 'text/html',
encoding => 'quoted-printable',
charset => 'US-ASCII'
},
body_str => $mail_body,
),
);
my $mail_to_users = join ', ', #{ $self->{config}->{mail_to} };
my $cc_mail_to_users = join ', ', #{ $self->{config}->{mail_cc_to} };
my $email = Email::MIME->create(
header => [
From => $self->{config}->{mail_from},
To => $mail_to_users,
Cc => $cc_mail_to_users,
Subject => $mail_subject,
],
parts => [#parts],
);
return $email;
}
sub send_mail {
my ( $self, $email ) = #_;
my $transport = Email::Sender::Transport::SMTP->new(
{
host => $self->{config}->{smtp_server}
}
);
eval { sendmail( $email, { transport => $transport } ); };
if ($#) {
return 0, $#;
}
else {
return 1;
}
}
Gmail and other mail servers will not allow unauthorized relay. In most cases you will need authorized access.
Here is what I use, after also trying many modules. Maybe this solution seems a little bit overdone, but it's easy to change for HTML with plain text as alternative or other attachments. Parameters of the transport are the most common ones.
#!perl
use strict;
use warnings;
use utf8;
use Email::Sender::Simple qw(sendmail try_to_sendmail);
use Email::Sender::Transport::SMTPS;
use Email::Simple ();
use Email::Simple::Creator ();
use Email::MIME;
send_my_mail('john.doe#hisdomain.com','Test','Test, pls ignore');
sub send_my_mail {
my ($to_mail_address, $subject, $body_text) = #_;
my $smtpserver = 'smtp.mydomain.com';
my $smtpport = 587;
my $smtpuser = 'me#mydomain.com';
my $smtppassword = 'mysecret';
my $transport = Email::Sender::Transport::SMTPS->new({
host => $smtpserver,
ssl => 'starttls',
port => $smtpport,
sasl_username => $smtpuser,
sasl_password => $smtppassword,
#debug => 1,
});
my $text_part = Email::MIME->create(
attributes => {
'encoding' => 'quoted-printable',
'content_type' => 'text/plain',
'charset' => 'UTF-8',
},
'body_str' => $body_text,
);
my $alternative_part = Email::MIME->create(
attributes => {
'content_type' => 'multipart/alternative',
},
parts => [ $text_part, ],
);
my $email = Email::MIME->create(
header_str => [
To => $to_mail_address,
From => "Website <$smtpuser>",
Subject => $subject,
],
attributes => {
'content_type' => 'multipart/mixed',
},
parts => [ $alternative_part ],
);
my $status = try_to_sendmail($email, { transport => $transport });
return $status;
}
Take a look at Email::Send::Gmail module. It might solve your problem.
I am trying to send HTML email using a script. I will have to use native unix things and Email::Mime since those are the only thing I found installed in the box i am stuck with. I am creating a Email::Mime message and sending it to sendmail.
But i keep getting Error: No recipient addresses found in header
I have seen other RUBY scripts using sendmail so that works for this box.
Can someone help me with what I might be doing wrong in the below snippet?
sub send_mail(){
use MIME::QuotedPrint;
use HTML::Entities;
use IO::All;
use Email::MIME;
# multipart message
my #parts = (
Email::MIME->create(
attributes => {
content_type => "text/html",
disposition => "attachment",
encoding => "quoted-printable",
charset => "US-ASCII",
},
body_str => "Hello there!",
),
);
my $email = Email::MIME->create(
header_str => [
To => 'abc#xxx.com',
From => 'abc#xxx.com',
Subject => "Test Email",
],
parts => [#parts],
);
# die $email->as_string;
# die YAML::XS::Dump(\%mail);
open(MAIL, "|/usr/sbin/sendmail -t");
print MAIL $email;
close (MAIL);
}
Thanks in advance.
print MAIL $email;
should be
print MAIL $email->as_string;
First of all, if your E-Mail server requires authentication (which most do of course), you need to specify a SMTP session:
$transport = EMail::Sender::Transport::SMTP::Persistent->new({
# host, port, ssl, etc
})
Furthermore, I think you don't actually need to create the content as an own MIME-content.
I did use something similar to this in my own work:
$email = Email::MIME->Create(
header_str => [ ... ],
body_str => $message,
attributes => {
charset => 'UTF-8',
encoding => 'base64',
content_type => 'text/html',
}
)
After sending your mail via sendmail($email, { transport => $transport }), you need to close the session through $transport->disconnect.
For your application you might to adapt several things like the actual sending protocol (if different from SMTP) or the attributes hash contents.
I am trying to send an email containing Russian text and subject in utf-8 encoding. Email is being received, when I open it in the web interface of gmail, everything is correct. But when I open the email in "The bat" client, the encoding is incorrect by default (I can set it manually to utf-8 though):
Subject: "Hello. Текст"
Body: "test email. Русский текст"
Instead of:
Subject: "Hello. Текст"
Body: "test email. Русский текст"
Code:
#!/usr/bin/perl
use utf8;
use strict;
use warnings;
use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTP ();
use Email::Simple ();
use MIME::Base64 qw( encode_base64 );
use open ':std', ':encoding(UTF-8)';
sub send_email
{
my $email_from = shift;
my $email_to = shift;
my $subject = shift;
my $message = shift;
my $smtpserver = 'smtp.gmail.com';
my $smtpport = 465;
my $smtpuser = 'user#gmail.com';
my $password = 'secret';
my $transport = Email::Sender::Transport::SMTP->new({
host => $smtpserver,
port => $smtpport,
sasl_username => $smtpuser,
sasl_password => $password,
debug => 1,
ssl => 1,
});
my $email = Email::Simple->create(
header => [
To => $email_to,
From => $email_from,
Subject => $subject,
],
body => $message,
);
$email->header_set( 'Content-Type' => 'text/html' );
$email->header_set( 'charset' => 'UTF-8' );
sendmail($email, { transport => $transport });
}
my $body = Encode::encode('utf-8', 'test email. Русский текст');
my $subject = Encode::encode('utf-8', 'Hello. Текст');
send_email('user#gmail.com', 'user#gmail.com', $subject, $body);
How to tell the email clients that the encoding is utf-8?
Give Email::Sender/Net::SMTP string of bytes
Email::Sender (Net::SMTP) expects bytes (see answer mentioned by user4035):
my $msg = $email->as_string();
utf8::encode($msg) if utf8::is_utf8($msg);
sendmail($msg, ...);
Email body encoding
Set all three MIME headers for "raw" utf-8 email body:
(You may use text/html instead of typical text/plain)
$email->header_set( 'MIME-Version' => '1.0' );
$email->header_set( 'Content-Type' => 'text/plain; charset=utf-8' );
$email->header_set( 'Content-Transfer-Encoding' => '8bit');
Your SMTP server should accept it and conduct conversions from "raw" (8-bit) utf-8 to another email encoding if necessary. Most modern email servers do it.
See Steffen Ullrich comment about notable exceptions among email providers [1&1 (GMX)].
Email headers encoding:
$email->header_raw_set( 'Subject' => Encode::encode('MIME-Header',$subject));
Debug procedure
Create minimal Email::Simple message, print it on utf-8 terminal
(print $email->as_string();) and post the result.
I am trying to send an email using MIME::Lite but the email will not send and I am not getting any errors.
Code:
my $subject = $Config->{email}->{subject};
my $from_email = $Config->{email}->{from_email};
my $message = $Config->{email}->{message};
my $smtp_server = $Config->{email}->{smtp_server};
my $msg = MIME::Lite->new
(
Subject => $subject,
From => $from_email,
To => $email,
Type => 'text/html',
Data => $message
);
$msg->send('smtp' ,$smtp_server );
Not much to go on there ...
Maybe try debugging?
$msg->send( 'smtp', $smtp_server, Debug=>1 );
And check all the values in $Config->{email} are as you would expect.
Why does the attachment(ca. 110KiB) split up in 10 parts(ca. 11KiB) when I send it with this script using Email::MIME?
#!/usr/bin/env perl
use warnings; use strict;
use Email::Sender::Transport::SMTP::TLS;
my $mailer = Email::Sender::Transport::SMTP::TLS->new(
host => 'smtp.my.host',
port => 587,
username => 'username',
password => 'password',
);
use Email::MIME::Creator;
use IO::All;
my #parts = (
Email::MIME->create(
attributes => {
content_type => 'text/plain',
disposition => 'inline',
encoding => 'quoted-printable',
charset => 'UTF-8',
},
body => "Hello there!\n\nHow are you?",
),
Email::MIME->create(
attributes => {
filename => "test.jpg",
content_type => "image/jpeg",
disposition => 'attachment',
encoding => "base64",
name => "test.jpg",
},
body => io( "test.jpg" )->all,
),
);
my $email = Email::MIME->create(
header => [ From => 'my#address', To => 'your#address', Subject => 'subject', ],
parts => [ #parts ],
);
eval {
$mailer->send( $email, {
from => 'my#address',
to => [ 'your#address' ],
} );
};
die "Error sending email: $#" if $#;
I had a similar case using MIME::Lite and Net::SMTP::TLS (using TLS rather than SSL because connection to smtp.gmail.com was not working with SSL) in my Perl script to send email with spreadsheet attachments through a gmail account, whereby the spreadsheet attachments were being broken up into multiple 10kb files.
Solution was to replace Net::SMTP::TLS with Net::SMTP::TLS::ButMaintained, which I hadn't initially seen. Newer TLS module works great.
I can offer you a workaround: using MIME::Lite instead