Gossamer Forum
Home : Products : Gossamer Links : Discussions :

Links::send_email get_body with subject

Quote Reply
Links::send_email get_body with subject
Hi there,

just wanted to share and kind of write down for myslef the following.
I use another way to send E-Mails and felt it was kind of handy not to get only the mail body but also the subject.
Not sure if this is the best way but I found some place in Links.pm in


Code:
sub send_email {
...
my $mail = new GT::Mail;
$mail->top_part($top);

+ return {
+ body => $mail->{head}->{data},
+ subject => $mail->{head}->{header_lines}->{subject}[0]
+ } if $opts->{get_body_and_subject};
+
my %send_opts;
if ($CFG->{db_smtp_server}) {

Now you get:

Code:
$mail_stuff = Links::send_email('mail_template.eml',
{ %$vars, %ENV },
{ get_body_and_subject => 1 });

Happy to hear any comments

Niko
Quote Reply
Re: [el noe] Links::send_email get_body with subject In reply to
Hi,

Looks good :) I wrote my own function to send emails, which allows me to send both html and plain emails (using multipart):

Code:
sub do_emailing_new {
# Plugins::Emails::do_emailing_new("foo_bar_template","Some subject",$opts)

use MIME::Lite;
use MIME::Base64;
use Encode;
use Links::SiteHTML;

use Email::MIME;
use Email::Address::XS;
use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTP;

my ($template,$subject,$opts) = @_;

#$subject = "foo é shorter";

my $to = $opts->{to};

# just in case they don't have a unique_id yet... but this should never happen
my $from = $opts->{from} || '"Andy" <andy@ultranerds.co.uk>';

my $html = Links::SiteHTML::display($template, { %$opts } );
my $text = Links::SiteHTML::display("${template}_txt", { %$opts }, { compress => 0 } );

$html = decode( 'utf-8', $html );
$text = decode( 'utf-8', $text );

use Email::MIME;
use Email::Address::XS;
use Email::Sender::Simple qw(sendmail);
use IO::All;

# multipart message
my @message_parts = (
Email::MIME->create(
body_str => $text,
attributes => {
encoding => 'quoted-printable',
content_type => "text/plain",
disposition => "inline",
charset => "UTF-8",
}
),
Email::MIME->create(
body_str => $html,
attributes => {
encoding => 'quoted-printable',
charset => "UTF-8",
content_type => "text/html",
disposition => "inline",
}
)
);


my @all_parts;
push @all_parts, Email::MIME->create(
parts => \@message_parts, # add all the message parts into here...
attributes => {
content_type => "multipart/alternative"
}
);


if ($opts->{attach_file}) {

my $filename = (reverse split /\//, $opts->{attach_file})[0];

push @all_parts, Email::MIME->create(
attributes => {
filename => $filename,
content_type => "application/pdf",
encoding => "base64",
name => $filename,
},
body => io( $opts->{attach_file} )->binary->all,
)
}

# use Data::Dumper;
# print $IN->header;
# print Dumper(@all_parts);

my $email = Email::MIME->create(
header_str => [
From => $from,
To => [ $to ],
Subject => $subject
],
parts => \@all_parts,
attributes => {
charset => "UTF-8",
content_type => "multipart/mixed",
}
);

# print qq|Structure: | . $email->debug_structure. "\n\n";
# exit;

=cut use this if you want to use smtp to send
my $transport = Email::Sender::Transport::SMTP->new({
host => 'smtp.gmail.com',
port => 465,
ssl => 1,
sasl_username => 'xxx',
sasl_password => 'xxx'
});
=cut

# send via sendmail
sendmail($email->as_string);

# send via smtp
# sendmail($email->as_string, { transport => $transport });

}


You call with:

Code:
Plugins::Emails::do_emailing_new("foo_bar_template","Some subject",$opts)

($opts just includes "from", "to" and any other params you want to pass along)

In this example you would have a plain text version of the email in:

foo_bar_template_txt.html

and then the HTML version as:

foo_bar_template.html

It's proven really helpful and helps with getting into peoples inboxes as well :)

Andy (mod)
andy@ultranerds.co.uk
Want to give me something back for my help? Please see my Amazon Wish List
GLinks ULTRA Package | GLinks ULTRA Package PRO
Links SQL Plugins | Website Design and SEO | UltraNerds | ULTRAGLobals Plugin | Pre-Made Template Sets | FREE GLinks Plugins!
Quote Reply
Re: [Andy] Links::send_email get_body with subject In reply to
Hi Andy,

Thanks for sharing that code. I guess we had a similar task. I will have to clean up mine a little and publish it here, maybe we can discuss some pros and cons.
One thing I added with MIME::Lite:

Code:
use MIME::Lite;
BEGIN { $MIME::Lite::VANILLA = 1; }
my $xmailer = "my personal mailer";
...
my $msg = MIME::Lite->new(
From => $from,
To => $mail->{to},
Cc => $mail->{cc},
Bcc => $bcc,
Type => 'multipart/mixed',
Subject => $subject,
"X-Mailer" => $xmailer,
"Return-Path" => $return_path,
);

Otherwise there is the MIME::Lite header, as far as I remember I enhanced the "I am not spam" thing.
On the other hand your way there probably wonīt be the MIME::Lite header.

Regards

Niko

Last edited by:

el noe: Jun 12, 2020, 4:36 AM
Quote Reply
Re: [el noe] Links::send_email get_body with subject In reply to
Hi,

My original version did use MIME::Lite, but unfortunatly it broken the multipart stuff, and I could never get it to work properly. Email::MIME offered a way to do this. I'm pretty sure you can also pass in the custom header using Email::MIME like:

Code:
my $email = Email::MIME->create(
header_str => [
From => $from,
To => [ $to ],
Subject => $subject,
"X-Mailer" => "foo bar"
],
parts => \@all_parts,
attributes => {
charset => "UTF-8",
content_type => "multipart/mixed",
}

Cheers

Andy (mod)
andy@ultranerds.co.uk
Want to give me something back for my help? Please see my Amazon Wish List
GLinks ULTRA Package | GLinks ULTRA Package PRO
Links SQL Plugins | Website Design and SEO | UltraNerds | ULTRAGLobals Plugin | Pre-Made Template Sets | FREE GLinks Plugins!
Quote Reply
Re: [Andy] Links::send_email get_body with subject In reply to
Hi Andy,

Found some time now. I will try both and see which one is faster but honestly I donīt care about fractions of seconds.
I had a lot of troubles with mails ending up in spam and so I am really curious about the headers and bodies that both variations create.
I appreciate your thoughts about pros and cons.

Maybe the false html if no file is available is an inspiration for you.

PDF seems to be some thing we needed both, I have textfiles I have to add from time to time so there are some additional lines.
Attachments with other endings I do not care about at the moment.

Code:
sub send_invoice {
my $results = shift;
my $mail;
my $mail_tpl;
$mail_tpl->{language} = 'de';
$mail_tpl->{txt_file} = 'eml_send_invoice_txt_' . $mail_tpl->{language} . '.eml';
$mail_tpl->{html_file} = 'eml_send_invoice_html_' . $mail_tpl->{language} . '.eml';
$mail_tpl->{txt} = Links::send_email($mail_tpl->{txt_file}, $results, { get_body_and_subject => 1 });
eval {
$mail_tpl->{html} = Links::send_email($mail_tpl->{html_file}, $results, { get_body_and_subject => 1 });
};
if ($@) {
$mail_tpl->{html}->{body} = min_text_to_html($mail_tpl->{txt}->{body});
}
$mail->{to} = 'default@recipient.domain';
$mail->{subject} = $mail_tpl->{txt}->{subject};
$mail->{txt_body} = $mail_tpl->{txt}->{body};
$mail->{html_body} = $mail_tpl->{html}->{body};
&send_mp_mail($mail);
}

Code:
sub send_mp_mail {
use MIME::Lite;
use MIME::Base64;
BEGIN { $MIME::Lite::VANILLA = 1; }
my $xmailer = "my x mailer";
use LWP::Simple;
use Unicode::UTF8simple;
use HTML::Entities;
use Encode;
my $uref = new Unicode::UTF8simple;
my $mail = shift;
my $suppress_archiv = shift || undef;
my $html_mail = $uref->toUTF8("iso-8859-1", $mail->{html_body});
my $txt_mail = $uref->toUTF8("iso-8859-1", $mail->{txt_body});
my $subject = "=?UTF-8?B?" . encode_base64(encode("utf8", decode_entities($mail->{subject})), "") . "?=";
my $from = $mail->{from} ? $mail->{from} : '"default company" <default@sender.domain>';
my $return_path = $mail->{return_path} ? $mail->{return_path} : 'default@sender.domain';
my $bcc = 'archiv@sender.domain' unless $suppress_archiv;
my $msg = MIME::Lite->new(
From => $from,
To => $mail->{to},
Cc => $mail->{cc},
Bcc => $bcc,
Type => 'multipart/mixed',
Subject => $subject,
"X-Mailer" => $xmailer,
"Return-Path" => $return_path,
);
my $part = MIME::Lite->new(
Type => 'multipart/alternative',
);
#add txt mail
my $att_text = MIME::Lite->new(
Type => 'text',
Data => $txt_mail,
Encoding => 'quoted-printable',
"X-Mailer" => $xmailer,
);
$att_text->attr('content-type' => 'text/plain; charset=UTF-8');
$part->attach($att_text);
#add html mail
my $att_html = MIME::Lite->new(
Type => 'text',
Data => $html_mail,
Encoding => 'quoted-printable',
"X-Mailer" => $xmailer,
);
$att_html->attr('content-type' => 'text/html; charset=UTF-8');
$part->attach($att_html);
$msg->attach($part);
if (defined @{$mail->{attachment_data}}) {
foreach (@{$mail->{attachment_data}}) {
$msg->attach(
Type => 'text/plain',
Data => $_->{data},
Disposition => 'attachment',
Filename => $_->{filename},
"X-Mailer" => $xmailer,
);
}
}
if (defined @{$mail->{attachment_urls}}) {
foreach (@{$mail->{attachment_urls}}) {
$msg->attach(
Type => 'application/pdf',
Data => get($_->{url}),
Disposition => 'attachment',
Filename => $_->{filename},
"X-Mailer" => $xmailer,
);
}
}
use Net::SMTP::SSL;
eval {
my $smtp;
$smtp = Net::SMTP::SSL->new('smtp.sender.domain', Port=>465, Debug=>0, Timeout=>20) or die "$_ Can't connect";
$smtp->auth('username', 'password') or die "Can't authenticate:" . $smtp->message();
$smtp->mail($from) or die "Error:" . $smtp->message();
$smtp->to($mail->{to}) or die "Error:" . $smtp->message();
if ($mail->{cc}) {
$smtp->cc($mail->{cc}) or die "Error:" . $smtp->message();
}
unless ($suppress_archiv) {
$smtp->bcc($bcc) or die "Error:" . $smtp->message();
}
$smtp->data() or die "Error:" . $smtp->message();
$smtp->datasend($msg->as_string) or die "Error:" . $smtp->message();
$smtp->dataend() or die "Error:" . $smtp->message();
$smtp->quit() or die "Error:" . $smtp->message();
};
if ($@) {
eval {
$msg->send;#fallback
};
}
}

Code:
sub min_text_to_html {
my $text = shift;
my $results;
for (split /^/, $text) {
if ($_ =~ /(.*)/) {
$_ = "$1<br>\n";
}
$results .= $_;
}
return $results;
}

Regards

Niko

Last edited by:

el noe: Jun 14, 2020, 11:54 AM
Quote Reply
Re: [el noe] Links::send_email get_body with subject In reply to
Hi,

Yes, I also don't care about fractions of sections (TBH, the SMTP side always slows it down anyway!)

For spam - you could try checking the structure is correct here:

Code:
print qq|Structure: | . $mail->debug_structure. "\n\n";


While lots of email clients will "figure it out", its amazing how many people get the email structures wrong (especially with regards to the html/plain text and attachment parts)

Another thing to test - would be to check your emails via http://mail-tester.com . Check your DKIM, SPF, DMARC records are all good (and that you are not on blacklistss)

Andy (mod)
andy@ultranerds.co.uk
Want to give me something back for my help? Please see my Amazon Wish List
GLinks ULTRA Package | GLinks ULTRA Package PRO
Links SQL Plugins | Website Design and SEO | UltraNerds | ULTRAGLobals Plugin | Pre-Made Template Sets | FREE GLinks Plugins!