How to send html body and plain attachment with perl Net::SMTP - perl

besides there is Mime:Lite etc. I have no other possibility to use Net::SMTP.
I am trying to send an email containing html message part and also an attachment containing text. I guess something is not in the right order or mime format may be incorrect?
I can get the attachment with the content but no message in the email body is displayed:
$smtp->data();
$smtp->datasend("Subject: ".$self->{SUBJECT}."\n");
$smtp->datasend("To: ".#{$self->{TO}}[0]."\n");
$smtp->datasend("From: ".$self->{FROM}."\n");
$smtp->datasend("MIME-Version: 1.0\n");
$smtp->datasend("Content-Type: multipart/mixed; boundary=\"frontier\"\n");
$smtp->datasend("\n--frontier\n");
$smtp->datasend("Content-Type: text/html; charset=\"UTF-8\" \n");
$smtp->datasend("<h3>".$self->{BODY}."<\/h3>");
$smtp->datasend("\n");
$smtp->datasend("--frontier\n");
$smtp->datasend("Content-Type: application/text; name= traps.txt \n");
$smtp->datasend("Content-Disposition: attachment; filename=\"traps.txt\"\n");
$smtp->datasend("\n");
$smtp->datasend($self->{BODY});
$smtp->datasend("\n");
$smtp->datasend("--frontier\n");
$smtp->dataend();
$smtp->quit;

Related

Problem with sending text attachment in Perl

I have a procedure to send mails as this:
sub SendMail {
my $subject = shift;
my #message = #_;
my $sender;
my $MIME_BOUNDARY = '====Multipart.Boundary.689464861147414354====';
my $now = strftime("%Y-%m-%d %H:%M:%S", localtime);
my #addresses = split(",", $ENV{ADMIN_MAIL});
my $sender = $ENV{USER} || $ENV{USERNAME};
$sender .= "\#" . hostname();
my $smtp = Net::SMTP->new($ENV{MAILHOST} || 'mailhost', Debug => 1);
unless ( $smtp ) {
die "Error while sending notification mail. Not connected to SMTP server.";
}
$smtp->mail( $addresses[0] );
$smtp->recipient( #addresses );
$smtp->data;
$smtp->datasend("From: $sender\n");
$smtp->datasend("To: " . join(",", #addresses) . "\n");
$smtp->datasend("Subject: $subject\n");
$smtp->datasend("Date: " . strftime("%a, %d %b %Y %H:%M:%S %z", localtime) . "\n");
if ( #log_messages ) {
$smtp->datasend("Mime-Version: 1.0\n");
$smtp->datasend("Content-Type: multipart/mixed; boundary=\"$MIME_BOUNDARY\"\n");
$smtp->datasend("This is a multipart message in MIME format.\n");
$smtp->datasend("--$MIME_BOUNDARY\n");
}
$smtp->datasend("Content-type: text/plain; charset=UTF-8\n");
$smtp->datasend("Content-Disposition: quoted-printable\n");
$smtp->datasend("\n");
foreach ( #message ) { $smtp->datasend("$_\n") }
$smtp->datasend("\n\n");
$smtp->datasend("Message from " . hostname() . " (PID=$$) sent by 'LogDumper.pl' at $now");
$smtp->datasend("\n");
if ( #log_messages ) {
$smtp->datasend("\n");
$smtp->datasend("--$MIME_BOUNDARY\n");
$smtp->datasend("Content-Type: text/plain; name=\"logs.txt\"\n");
$smtp->datasend("Content-Disposition: attachment; filename=\"logs.txt\"\n");
$smtp->datasend("\n");
foreach ( #log_messages ) { $smtp->datasend("$_\n") }
$smtp->datasend("\n");
$smtp->datasend("--$MIME_BOUNDARY--\n");
}
$smtp->dataend;
$smtp->quit;
}
The procedure works fine with plain text mails, i.e. empty #log_messages. However, if I try to attach a text file
my #log_messages;
push #log_messages, "Line 1";
push #log_messages, "Line 2";
SendMail("The Subject", "The Message");
then the mail is not sent.
Debug output is this:
Net::SMTP=GLOB(0x7a78a40)<<< 354 Start mail input; end with <CRLF>.<CRLF>
Net::SMTP=GLOB(0x7a78a40)>>> From: Domscheit#xxxxx
Net::SMTP=GLOB(0x7a78a40)>>> To: wernfried.domscheit#xxxxx.xxx
Net::SMTP=GLOB(0x7a78a40)>>> Subject: The Suject
Net::SMTP=GLOB(0x7a78a40)>>> Date: Mo, 01 Okt 2018 10:15:57 W. Europe Daylight Time
Net::SMTP=GLOB(0x7a78a40)>>> Mime-Version: 1.0
Net::SMTP=GLOB(0x7a78a40)>>> Content-Type: multipart/mixed; boundary="====Multipart.Boundary.689464861147414354===="
Net::SMTP=GLOB(0x7a78a40)>>> This is a multipart message in MIME format.
Net::SMTP=GLOB(0x7a78a40)>>> --====Multipart.Boundary.689464861147414354====
Net::SMTP=GLOB(0x7a78a40)>>> Content-type: text/plain; charset=UTF-8
Net::SMTP=GLOB(0x7a78a40)>>> Content-Disposition: quoted-printable
Net::SMTP=GLOB(0x7a78a40)>>> The Message
Net::SMTP=GLOB(0x7a78a40)>>> Message from xxxxx (PID=8072) sent by 'LogDumper.pl' at 2018-10-01 10:15:54
Net::SMTP=GLOB(0x7a78a40)>>> --====Multipart.Boundary.689464861147414354====
Net::SMTP=GLOB(0x7a78a40)>>> Content-Type: text/plain; name="logs.txt"
Net::SMTP=GLOB(0x7a78a40)>>> Content-Disposition: attachment; filename="logs.txt"
Net::SMTP=GLOB(0x7a78a40)>>> Line 1
Net::SMTP=GLOB(0x7a78a40)>>> Line 2
Net::SMTP=GLOB(0x7a78a40)>>> --====Multipart.Boundary.689464861147414354====--
Net::SMTP=GLOB(0x7a78a40)>>> .
Net::SMTP: Unexpected EOF on command channel at C:\Developing\Source\LogDumper.pl line 1271.
Apparently there is a missing or needless \n. I tried to put it almost everywhere but I don't get it working.
Update:
Actually it is working when I execute the script on Linux but not on my Windows development PC.
I think the problem is solved.
It works on production server at Linux
It works on development Windows PC when I am working in the office
It does not work on Windows when I am working at home and connected via VPN - nasty security department...
Well, it is not really solved but for me it is working fine. I did not test (yet) whether it fails over VPN also for one of the higher-level packages.

What are -- in email headers?

Recently i came across -- as a header of mail() function in php. I tried to google it out but didn't found any result so i am posting this question. While trying to edit my code i found that the id after these two -- should be unique.My php script to send email with attachement.
<?php
$file = "http://wpbrisk.com/download/email/email/doc1.pdf"; // Specify the Url of the attachment here
$filename = "doc1.pdf"; // Specify the name of the file here
$to="hudixt#gmail.com"; // Enter the mail to which you want to sent the attachement
$your_name = "Hudixt"; // Your name
$from_mail = "info#wpbrisk.com"; // Your email
$subject = "This is a mail with attachment."; // Subject
$message = "<div id='hello'>World</div>"; // message
// Get the content of the file
$content = file_get_contents($file);
$content = base64_encode($content);
$uid = md5(uniqid(time()));
$header = "From: ".$from_name." <".$from_mail.">\r\n";
$header .= "MIME-Version: 1.0\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"".$uid."\"\r\n\r\n";
$header .= "This is a multi-part message in MIME format.\r\n";
$header .= "--".$uid."\r\n";
$header .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
$header .= $message."\r\n\r\n";
$header .= "--".$uid."\r\n";
$header .= "Content-Type: application/octet-stream; name=\"".$filename."\"\r\n"; // use different content types here
$header .= "Content-Transfer-Encoding: base64\r\n";
$header .= "Content-Disposition: attachment; filename=\"".$filename."\"\r\n\r\n";
$header .= $content."\r\n\r\n";
$header .= "--".$uid."--";
mail($mailto, $subject, "", $header);
?>
Can you please tell me what this -- means in header and why it should be unique.
These "--ID--" lines are MIME part boundaries (see https://en.wikipedia.org/wiki/MIME). They are described in https://www.rfc-editor.org/rfc/rfc2046. They are used to separate different parts of a message.
According to RFC#2046 those only must be unique "enough". If you want to encapsulate an email into another one, the boundaries must not infer with each other, i.e. they have to be distinct. So it's a good idea to make them as unique "as possible and needed":
This implies that it is crucial that the composing agent be able
to choose and specify a unique boundary parameter value that does
not contain the boundary parameter value of an enclosing multipart
as a prefix.
(https://www.rfc-editor.org/rfc/rfc2046#section-5.1)
Seems like a MIME boundary to me...
Basically, when you have multiple types of content in an e-mail message, the different parts are separated using an ID. Each part is then preceded by '--' followed by the boundary. From the RFC:
Thus, a typical multipart Content-Type header field might look like this:
Content-Type: multipart/mixed;
boundary=gc0p4Jq0M2Yt08jU534c0p
This indicates that the entity consists of several parts, each itself with a structure that is syntactically identical to an RFC 822 message, except that the header area might be completely empty, and that the parts are each preceded by the line
--gc0p4Jq0M2Yt08jU534c0p
See http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html for more info.
To answer your last question, when you have an e-mail with text and attachment, the whole message will have Content-Type: multipart/mixed, the text will be text/plain, the attachment (suppose a word file) will be application/msword. Each new content-type part will be separated by '--' . $boundary. The boundary is chosen to be unique and different from the other message parts so that it doesn't appear inside either of them - when the application interpreting the e-mail contents finds $boundary it must be safe to assume that's an intended boundary and not just a fluke inside the message.
Hope that helps!

hotmail not receiving image attachment content

I'm trying to send a raw email with image attachments via AmazonSES using PHP. It works great when I send the email to a gmail account but hotmail accounts are receiving empty attached images. In other words, hotmail seems to recognize that there are attachments and these attachments have the correct name that i specified, it's just that they are always empty, sized 0 bytes. Googling is not helping... Thanks in advance!
$amazonSES = new AmazonSES();
// if (empty($attach)==0) {
// $response = $amazonSES->send_email(AWS_SES_FROM_EMAIL,
// array('ToAddresses' => array($to)),
// array('Subject.Data' => $subject,'Body.Text.Data' => $messagein,)
// );
// } else {
$rstring = 'ajfas90lsjhntlen89y34oi598';
$message= "To: ".$to."\n";
$message.= "From: " . AWS_SES_FROM_EMAIL . "\n";
$message.= "Subject: " . $subject . "\n";
$message.= "MIME-Version: 1.0\n";
$message.= 'Content-Type: multipart/mixed; boundary="ARandomString'.$rstring.'"';
$message.= "\n\n";
$message.= "--ARandomString$rstring\n";
$message.= 'Content-Type: text/plain; charset="utf-8"';
$message.= "\n";
$message.= "Content-Transfer-Encoding: 7bit\n";
$message.= "Content-Disposition: inline\n";
$message.= "\n";
$message.= $messagein;
$message.= "\n\n";
$message.= "--ARandomString$rstring\n";
foreach ($attach as $attachment) {
// $message.= "Content-ID: \<77987_SOME_WEIRD_TOKEN_BUT_UNIQUE_SO_SOMETIMES_A_#domain.com_IS_ADDED\>\n";
$message.= "Content-ID: \<". md5(uniqid(rand(), true)) ."#biomechanico.com\>\n";
$message.= 'Content-Type: application/zip; name="shell.zip"';
$message.= "\n";
$message.= "Content-Transfer-Encoding: base64\n";
$message.= 'Content-Disposition: attachment; filename="' . $attachment["name"] . '"';
$message.= "\n" . base64_encode(file_get_contents($attachment["file"])) . "\n";
$message.= "--ARandomString$rstring\n";
}
$response = $amazonSES->send_raw_email(array(
'Data'=> base64_encode($message)),
array('Source'=>AWS_SES_FROM_EMAIL, 'Destinations'=> $to));
You are producing a malformed message.
Consider using a proper library for generating mail messages, instead of stitching them together from raw strings.
Otherwise, here’s what I notice right away.
The final multipart boundary must be terminated by an extra --, i.e. the last line must be:
--ARandomStringajfas90lsjhntlen89y34oi598--
rather than
--ARandomStringajfas90lsjhntlen89y34oi598
In the attachment parts, you do not have a blank line between the Content-Disposition header line and the body.
Message lines must not be longer than 998 characters, but your Base64-encoded attachment data, however long, is always on a single line.
As far as I understand PHP, your syntax for Content-ID in the attachment parts is wrong, in that it produces Content-ID: \<whatever\> but should produce Content-ID: <whatever>
Lines must be terminated by CR LF (\r\n), but you have LF (\n).
A good way to debug message problems is to take the actual full generated message source ($message) and run it through Message Lint. If the above suggestions do not help, please post the generated message source rather than the PHP code.
For the Internet message format, please refer to RFC 5322. For the multipart message syntax, please refer to RFC 2046.

Extra spaces being added to PHP mail headers

I'm sending a multipart HTML email using PHP's mail() function. In my Postfix configuration I have my SMTP server set to Amazon's SES. Here is the PHP for sending the email:
$boundary = uniqid("HTMLDEMO");
$headers = "From: me#mydomain.com\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/alternative; boundary = ".$boundary."\r\n\r\n";
// plain text
$content = "--".$boundary."\r\n" .
"Content-Type: text/plain; charset=ISO-8859-1\r\n" .
"Content-Transfer-Encoding: base64\r\n\r\n" .
chunk_split(base64_encode($plaintext_message));
// HTML
$content .= "--".$boundary."\r\n" .
"Content-Type: text/html; charset=ISO-8859-1\r\n" .
"Content-Transfer-Encoding: text/html \r\n\r\n" .
"<html><body>".$html_message."</body></html>";
//send message
mail($to, $subject, $content, $headers);
When I echo the message content, this is what I see in the browser:
--HTMLDEMO527d8d851e72f
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: base64
VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCB2ZXJzaW9uIQ==
--HTMLDEMO527d8d851e72f
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: text/html
<html><body><p>My message here.</p></body></html>
But when I view the message source in Gmail, I now see this (including the message headers):
From: me#mydomain.com
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary = HTMLDEMO527d8d851e72f
Message-ID: <blah-blah-blah#email.amazonses.com>
Date: Sat, 9 Nov 2013 01:19:02 +0000
X-SES-Outgoing: 2013.11.09-12.34.5.67
--HTMLDEMO527d8d851e72f
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: base64
VGhpcyBpcyB0aGUgcGxhaW4gdGV4dCB2ZXJzaW9uIQ==
--HTMLDEMO527d8d851e72f
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: text/html
The multipart headers are now double-spaced, causing the HTML to display as plain text. SES is clearly modifying the message headers (it added Message-ID, Date, and X-SES-Outgoing), so could that also be the culprit for the extra spaces in the multipart headers? When I send an identical email from a non-Amazon server, it comes through normally and renders the HTML like it should.
Also, when I send it as a simple HTML email (not multipart), then it works just fine.
Thanks.
I had got the same issue and I resolved it by changing the end of line character to '\n' instead of '\r\n'.

Perl MIME::Parser and encoding in nested bodys (message/rfc_822)

arghhh, it's not easy. I'm trying to parse some mails with perl. Let's take an example:
From: abc#def.de
Content-Type: multipart/mixed;
boundary="----_=_NextPart_001_01CBE273.65A0E7AA"
To: ghi#def.de
This is a multi-part message in MIME format.
------_=_NextPart_001_01CBE273.65A0E7AA
Content-Type: multipart/alternative;
boundary="----_=_NextPart_002_01CBE273.65A0E7AA"
------_=_NextPart_002_01CBE273.65A0E7AA
Content-Type: text/plain;
charset="UTF-8"
Content-Transfer-Encoding: base64
[base64-content]
------_=_NextPart_002_01CBE273.65A0E7AA
Content-Type: text/html;
charset="UTF-8"
Content-Transfer-Encoding: base64
[base64-content]
------_=_NextPart_002_01CBE273.65A0E7AA--
------_=_NextPart_001_01CBE273.65A0E7AA
Content-Type: message/rfc822
Content-Transfer-Encoding: 7bit
X-MimeOLE: Produced By Microsoft Exchange V6.5
Content-class: urn:content-classes:message
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----_=_NextPart_003_01CBE272.13692C80"
From: bla#bla.de
To: xxx#xxx.de
This is a multi-part message in MIME format.
------_=_NextPart_003_01CBE272.13692C80
Content-Type: multipart/alternative;
boundary="----_=_NextPart_004_01CBE272.13692C80"
------_=_NextPart_004_01CBE272.13692C80
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
=20
Viele Gr=FC=DFe
------_=_NextPart_004_01CBE272.13692C80
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
<html>...</html>
------_=_NextPart_004_01CBE272.13692C80--
------_=_NextPart_003_01CBE272.13692C80
Content-Type: application/x-zip-compressed;
name="abc.zip"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="abc.zip"
[base64-content]
------_=_NextPart_003_01CBE272.13692C80--
------_=_NextPart_001_01CBE273.65A0E7AA--
This mail is sent from Outlook with another attached message. As you can see, this is a very complex mail with many different content types (text/plain, text/html, message/rfc_822, application/xyz)...
And the rfc_822 part is the problem. I've written a script in Perl 5.8 (Debian Squeeze) to parse this message with MIME::Parser.
use MIME::Parser;
my $parser = MIME::Parser->new;
$parser->output_to_core(1);
my $top_entity = $parser->parse(\*STDIN);
my $plain_body = "";
my $html_body = "";
my $content_type;
foreach my $part ($top_entity->parts_DFS) {
$content_type = $part->effective_type;
$body = $part->bodyhandle;
if ($body) {
if ($content_type eq 'text/plain') {
$plain_body = $plain_body . "\n" if ($plain_body ne '');
$plain_body = $plain_body . $body->as_string;
} elsif ($content_type eq 'text/html') {
$html_body = $html_body . "\n" if ($html_body ne '');
$html_body = $html_body . $body->as_string;
}
}
}
# parsing of attachment comes later
print $plain_body;
The first message part (base64-content) contains german umlauts, which are shown correctly at STDOUT. The nested rfc_822 message is parsed by MIME::Parser automatically and is pooled with the top level body as one entity. This nested rfc_822 contains also german umlauts in quoted-printable as you can see. But these are not shown correctly at STDOUT. When doing a
utf8::encode($plain_body);
before print, the quoted-printable umlauts are shown correctly, but not the base64 encoded ones. I'm trying now for hours to extract the rfc_822 seperatly and doing some encoding, but nothing helps. Who else can help?
Regards
Assuming that your console displays UTF-8, this make sense.
It correctly shows what you have decoded, but, of course, latin1 characters are not shown correctly.
Later, you do a conversion to UTF-8, but this does not make sense if the data is already UTF8. So only the former latin1 umlauts are shown.
There is no way to get this right without looking at the "charset" in the content-type and acting accordingly.