Send html in email with Catalyst and Catalyst::Plugin::Email - plugins

I have been reading about Catalyst framework and I am trying to send an email with HTML content without success.
I tried to use Catalyst::Plugin::Email, just as the example here. The email is sent, but all the content is showed in plain text.
sub send_email : Local {
my ($self, $c) = #_;
$c->email(
header => [
To => 'me#localhost',
Subject => 'A TT Email',
],
body => $c->view('Web')->render($c, 'email.tt', {
additional_template_paths => [ $c->config->{root} . '/email_templates'],
email_tmpl_param1 => 'foo'
}
),
);
# Redirect or display a message
}
I also read about Catalyst::View::Email::Template, but I chouldn't install it.
Any idea?

I am now available to send HTML emails with Catalyst::Plugin::Email. From documentation:
"email() accepts the same arguments as Email::MIME::Creator's create()."
Looking into Email::MIME::Creator, the create method structure is:
my $single = Email::MIME->create(
header_str => [ ... ],
body_str => '...',
attributes => { ... },
);
my $multi = Email::MIME->create(
header_str => [ ... ],
parts => [ ... ],
attributes => { ... },
);
"Back to attributes. The hash keys correspond directly to methods or modifying a message from Email::MIME::Modifier. The allowed keys are: content_type, charset, name, format, boundary, encoding, disposition, and filename. They will be mapped to "$attr_set" for message modification."
This is the code it is working:
sub send_email : Local {
my ($self, $c) = #_;
$c->email(
header => [
To => 'me#localhost',
Subject => 'A TT Email',
],
body => $c->view('Web')->render($c, 'email.tt', {
additional_template_paths => [ $c->config->{root} . '/email_templates'],
email_tmpl_param1 => 'foo'
}
),
attributes => {
content_type => 'text/html',
charset => 'utf-8'
},
);
# Redirect or display a message
}

Related

How to inline images with Perl Email::Mime?

I am trying to send HTML email with inline images. I will have to use native unix things and Email::Mime since those are the only things I found installed in the box i am stuck with. I am creating a Email::Mime message and sending it to sendmail. I am using cid for in-lining the image but for some reason I keep getting the image as an attachment.
Can someone help me, code snippet is below.
sub send_mail(){
use MIME::QuotedPrint;
use HTML::Entities;
use IO::All;
use Email::MIME;
$boundary = "====" . time() . "====";
$text = "HTML mail demo\n\n"
. "This is the message text\n"
. "Voilà du texte qui sera encodé\n";
$plain = encode_qp $text;
$html = encode_entities($text);
$html =~ s/\n\n/\n\n<p>/g;
$html =~ s/\n/<br>\n/g;
$html = "<p><strong>" . $html . "</strong></p>";
$html .= '<p><img src="cid:123.png" class = "mail" alt="img-mail" /></p>';
# multipart message
my #parts = (
Email::MIME->create(
attributes => {
content_type => "text/html",
encoding => "quoted-printable",
charset => "US-ASCII",
},
body_str => "<html> $html </html>",
),
Email::MIME->create(
attributes => {
content_type => "image/png",
name => "pie.png",
disposition => "Inline",
charset => "US-ASCII",
encoding => "base64",
filename => "pie.png",
"Content-ID" => "<123.png>",
path => "/local_vol1_nobackup/user/ramondal/gfxip_gfx10p2_main_tree03/src/verif/ge/tb",
},
body => io("pie.png")->binary->all,
),
);
my $email = Email::MIME->create(
header_str => [
To => 'abc#xyz.com',
Subject => "Test Email",
],
parts => [#parts],
);
# die $email->as_string;
open(MAIL, "|/usr/sbin/sendmail -t") or die $!;
print MAIL $email->as_string;
close (MAIL);
}
There are two problems with your code.
First, it should be a Content-Id: <123.png> MIME header but your code instead produces a content-id=<123.png> parameter for the Content-Type header. To fix this don't add the Content-Id to the attributes but instead as header_str:
...
Email::MIME->create(
header_str => [
"Content-ID" => "123.png",
],
attributes => {
content_type => "image/png",
...
Second, the code creates a multipart/mixed content type for the mail. But the image and the HTML are related, so it should be a multipart/related content-type:
...
my $email = Email::MIME->create(
header_str => [
To => 'abc#xyz.com',
Subject => "Test Email",
],
attributes => {
content_type => 'multipart/related'
},
parts => [#parts],
);
...

Unable to attach attachment while sending mail

Can anyone please help with attaching two text files while sending email using Email::Simple. I am able to receive mail but without the attachments
I have tried a lot but couldn't make it work, not sure if I am having the incorrect modules. I did not want to use MIME::Lite because of the recommendation by the creator of MIME::Lite. I basically wanted to use my own SMTP details, and got Email::Sender as recommendation. Everything works except the attachment.
use strict;
use warnings;
use Email::Sender::Simple qw(sendmail);
use Email::Sender::Transport::SMTP ();
use Email::Simple ();
use Email::Simple::Creator ();
use Email::Sender::Transport::SMTP::TLS;
use Email::MIME;
use IO::All;
my $transport = Email::Sender::Transport::SMTP::TLS->new({
host => 'smtp.office365.com',
port => 587,
sasl_username => 'abcsender#abc.com',
sasl_password => 'P#ssw0rd#123',
username => 'abcsender#abc.com',
password => 'P#ssw0rd#123'
});
my #parts = (
Email::MIME->create(
attributes => {
content_type => "text/plain",
filename => "/tmp/ERROR1493720941.log",
charset => "US-ASCII",
disposition =>"attachment",
},
body => io( "/tmp/ERROR1493720941.log" )->all,
),
Email::MIME->create(
attributes => {
content_type => "text/plain",
filename => "/tmp/FAILED1493720941.log",
charset => "US-ASCII",
disposition =>"attachment",
},
body => io( "/tmp/FAILED1493720941.log" )->all,
),
);
my $email = Email::Simple->create(
header => [
To => 'gsrivastava#abc.com',
From => 'abcsender#abc.com',
Subject => 'Hi!',
],
body => "Hello",
parts => [ #parts ],
);
sendmail($email, { transport => $transport });
As asked by #DaveCross in comment, here is the output of $email->as_string
$VAR1 = 'To: gsrivastava#abc.com^M
From: abcsender#abc.com^M
Subject: Hi!^M
Date: Sun, 7 May 2017 07:58:46 -0400^M
^M
Hello^M
Turns out that this is a pretty simple mistake to make. You are creating a MIME email, but when you get to creating the actual email object, you use this code:
my $email = Email::Simple->create(
header => [
To => 'gsrivastava#abc.com',
From => 'abcsender#abc.com',
Subject => 'Hi!',
],
body => "Hello",
parts => [ #parts ],
);
Email::Simple isn't intended for MIME mail messages, so it doesn't understand the parts attribute and ignores it. To create a MIME email, you need to use Email::MIME.
my $email = Email::MIME->create(
header => [
To => 'gsrivastava#abc.com',
From => 'abcsender#abc.com',
Subject => 'Hi!',
],
parts => [ #parts ],
);
Note that I've removed the body attribute. MIME emails can't have both parts and a body. The solution is to add another element to #parts that contains your body text.
my #parts = (
Email::MIME->create(
attributes => {
content_type => 'text/plain',
disposition => 'attachment',
charset => 'US-ASCII',
encoding => 'quoted-printable',
},
body_str => 'Hello',
),
...
);

How to access individual elements of perl Hashed object?

I'm a non-programmer attemting to retrieve useful info from our InfoBlox DHCP boxes. I've installed the Perl API and can make some use of it.
I've got an output from the Data::Dumper "thingie" that appears to have some of the info I want. I'd like to directly reference some of that data but I'm unsure how.
print Dumper(\$object)
Here is part of the Data::Dumper output;
$VAR1 = \bless( {
'network' => '10.183.1.0/24',
'override_lease_scavenge_time' => 'false',
'enable_ifmap_publishing' => 'false',
'low_water_mark_reset' => '10',
'use_lease_time' => 0,
'use_enable_option81' => 0,
'network_container' => '/',
'override_ddns_ttl' => 'false',
'rir' => 'NONE',
'network_view' => bless( {
<snip> --------------------------------------
'extattrs' => {
'Use' => bless( {
'value' => 'Voip'
}, 'Infoblox::Grid::Extattr' )
},
<snip> --------------------------------------
'members' => [
bless( {
'ipv4addr' => '10.85.9.242',
'name' => 'ig3-app3.my.net'
}, 'Infoblox::DHCP::Member' ),
bless( {
'ipv4addr' => '10.85.9.210',
'name' => 'ig3-app1.my.net'
}, 'Infoblox::DHCP::Member' ),
bless( {
'ipv4addr' => '10.85.9.226',
'name' => 'ig3-app2.my.net'
}, 'Infoblox::DHCP::Member' )
],
'override_ignore_client_identifier' => 'false',
'email_list' => undef,
'rir_registration_status' => '??
}, 'Infoblox::DHCP::Network' );
How do I view the elements? ie ...
print $object{members->name};
print $object{members->ipv4addr};
print $object{extattrs->Use->value};
I've found the API dox insufficiant for my skill level:) The data I'd like to pull remains just out of reach.
my #retrieved_objs = $session->search (
object => "Infoblox::DHCP::Network",
network => '.*\.*\.*\..*',
);
foreach $object ( #retrieved_objs ) {
my $network = $object->network;
my $comment = $object->comment;
my $extattrs = $object->extattrs;
my $options = $object->options;
print $network, " network ", $comment, " ", $extattrs, " ", $options, "\n";
}
-------- output ---
10.183.2.0/24 network HASH(0x6a2f038) ARRAY(0x1d20eb0)
10.192.1.0/24 network HASH(0x9df6540) ARRAY(0x9df5468)
10.192.2.0/24 network HASH(0xa088fc8) ARRAY(0xa089718)
You shouldn't try to access the internal values of an object directly. The module - in this case Infoblox::DHCP::Network will provide methods that allow you to read or manipulate the values properly.

LWP Get Large File Download Headers Missing

This post is follow on work related to LWP GET large file download. That post was regarding an error from LWP when trying to pass arguments in the header incorrectly. Now I am posting the changes I made and how I am trying to debug the approach. This discussion should be very informative for those interested in POST vs GET header formation, and what the server receives while using the CGI package. It is not information easily found on the net.
Here is my client code snip:
my $bytes_received = 0; # vars used below are set prior to this point
my $filename = $opt{t}."/$srcfile";
open (FH, ">", "$filename") or $logger->error( "Couldn't open $filename for writing: $!" );
my $ua = LWP::UserAgent->new();
my $target = $srcfile;
my $res = $ua->get(
$url,
':content_cb' => \&callback,
'api' => 'olfs', # Note attempted use of different types of quotes had no impact
"cmd" => 'rfile',
"target" => $target,
"bs" => $bs
);
print $logger->info("$bytes_received bytes received");
sub callback{
my($chunk, $res) = #_;
$bytes_received += length($chunk);
print FH $chunk;
}
Here is the server snip (cgi script):
my $query = new CGI;
my $rcvd_data = Dumper($query);
print $rcvd_data;
Here is the output from a GET:
$VAR1 = bless( {
'.parameters' => [],
'use_tempfile' => 1,
'.charset' => 'ISO-8859-1',
'.fieldnames' => {},
'param' => {},
'.header_printed' => 1,
'escape' => 1
}, 'CGI' );
Here is a client with a POST request:
my $ua = new LWP::UserAgent();
local $HTTP::Request::Common::DYNAMIC_FILE_UPLOAD = 1;
my $req =
POST
$url,
'Content_Type' => 'form-data',
'Content' => {
"api" => 'olfs',
"cmd" => 'wfile',
"target" => $target,
"tsize" => $file_size,
"bs" => $bs,
"filename" => [ $file ] };
# HTTP::Message calls set_content, which appears to set the subroutine for content
# LWP::UserAgent
# LWP::Protocol::file::request sends content in chunks
#
$req->content( $req->content() );
$logger->info("Uploading: $file");
my $resp = $ua->request($req);
Here is the output on the server, just like before but now from the POST:
'.parameters' => [
'cmd',
'bs',
'api',
'target',
'filename',
'tsize'
],
'use_tempfile' => 1,
'.tmpfiles' => {
'*Fh::fh00001random23' => {
'info' => {
'Content-Type' => 'text/plain',
'Content-Disposition' => 'form-data; name="filename"; filename="random23"'
},
'name' => bless( do{\(my $o = '/usr/tmp/CGItemp33113')}, 'CGITempFile' ),
'hndl' => bless( \*Fh::fh00001random23, 'Fh' )
}
},
'.charset' => 'ISO-8859-1',
'.fieldnames' => {},
'param' => {
'cmd' => [
'wfile'
],
'bs' => [
'buffer1'
],
'api' => [
'olfs'
],
'target' => [
'random23'
],
'tsize' => [
'1073741824'
],
'filename' => [
$VAR1->{'.tmpfiles'}{'*Fh::fh00001random23'}{'hndl'}
},
'escape' => 1,
'.header_printed' => 1
}, 'CGI' );
In short, you can see in the POST dump the "key" / "value" pairs, ie "target => random23". In the GET dump I do not find any keys or values from what I submitted on the client side. Can that be explained, or what do I need to do so as to extract key / value pairs in the CGI script?
You're passing your form variables as HTTP headers.
Like I previously mentioned, if you want to build a url, you can use URI.
$url = URI->new($url);
$url->query_form(
api => 'olfs',
cmd => 'rfile',
target => $target,
bs => $bs,
);

Why does Email::MIME split up my attachment?

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