PHP mail() attachment is corrupt - php

I have been struggling with trying to send an email with an attachment using PHP. It used to work but the message body was scrambled. Now I have got the message body to work but the attachment corrupts. I used to use base64 encoding for the message body but now use 7bit. Can anyone tell me what I am doing wrong?
PS please do not tell me that I should be using a pre-made class to do this. I have tried several and they have all failed to work. If I do not overcome these problems I will never learn how to do it properly. Thanks
//define the receiver of the email
$to = 'a#something.co.uk';
//define the subject of the email
$subject = 'Your Disneyland Paris entry';
//create a boundary string. It must be unique
//so we use the MD5 algorithm to generate a random hash
$random_hash = md5(date('r', time()));
//define the headers we want passed. Note that they are separated with \n
$mime_boundary = "<<<--==+X[".md5(time())."]";
$path = $_SERVER['DOCUMENT_ROOT'].'/two/php/';
$fileContent = chunk_split(base64_encode(file_get_contents($path.'CTF_brochure.pdf')));
$headers .= "From: info#blah.org.uk <info#blah.org.uk>"."\n";
$headers .= "MIME-Version: 1.0\n" .
"Content-Type: multipart/mixed;\n" .
" boundary=\"{$mime_boundary}\"";
$message = "This is a multi-part message in MIME format.\n";
$message .= "\n";
$message .= "--".$mime_boundary."\n";
$message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
$message .= "Content-Transfer-Encoding: 7bit\n";
$message .= "\n";
$message .= "messagebody \n";
$message .= "--".$mime_boundary."" . "\n";
$message .= "Content-Type: application/octet-stream;\n";
$message .= " name=\"CTF-brochure.pdf\"" . "\n";
$message .= "Content-Transfer-Encoding: 7bit \n";
$message .= "Content-Disposition: attachment;\n";
$message .= " filename=\"CTF_brochure.pdf\"\n";
$message .= "\n";
$message .= $fileContent;
$message .= "\n";
$message .= "--".$mime_boundary."--\n";
//send the email
$mail_sent = mail($to, $subject, $message, $headers);
//if the message is sent successfully print "Mail sent". Otherwise print "Mail failed"
echo $mail_sent ? "Mail sent" : "Mail failed";

I could be wrong but I believe you will have to encode the PDF somehow, 7bit won't work as the PDF file will have content outside the range. Why not use base64 for the PDF?

I would suggest looking at phpmailer if you want to do complex email.

I know you've said about pre-built classes but there is a reason that people do this - why re-invent the wheel? I use SwiftMailer for projects - it couldn't be simpler. See this SwiftMailer example for 13 lines (including some blank ones) of how to create a message, add an attachment and send.
As to the resolution of your actual query, upvote to Josh's answer - I'd second changing the encoding and seeing how you get on. Have you tried getting an example email message which has an attachment that works, and examining the raw data?

Related

PHP mail - Spam Problems

I am trying to generate an email on signing up to website, I am using PHP to create and send the email. My domain has both SPF and DKIM running on it. However when i spam check my email i get this:
[SPF] srv61.hosting24.com does not allow your server 31.220.105.111 to use face159#srv61.hosting24.com
[Sender ID] srv61.hosting24.com does not allow your server 31.220.105.111 to use face159#srv61.hosting24.com
Your message is not signed with DKIM
I have contacted my hosting and they confirm that all the authentication systems are working on there end, so i must be doing something wrong in the PHP code but for the life of me i can't find what here is how i generate the email:
//Emails link to voucher
//create a boundary for the email. This
$boundary = uniqid('np');
$subject = "The Forum - Little Thank You";
//headers - specify your from email address and name here
//and specify the boundary for the email
$headers = "MIME-Version: 1.0\r\n";
$headers .= "From: TheForum#freewifisystems.co.uk" . "\r\n";
$headers .= "To: " . $email . "\r\n";
$headers .= "Content-Type: multipart/alternative;boundary=" . $boundary . "\r\n";
//here is the content body
$message = "This is a MIME encoded message.";
$message .= "\r\n\r\n--" . $boundary . "\r\n";
$message .= "Content-type: text/plain;charset=utf-8\r\n\r\n";
//Plain Email
$content2 = "plain text email here";
//Plain text body
$message .= "Hello,\nThis is a text email as HMTL is dissable, Please enable HTML to continue. \n\nRegards,\nThe Forum";
$message .= "\r\n\r\n--" . $boundary . "\r\n";
$message .= "Content-type: text/html;charset=utf-8\r\n\r\n";
//Html body
$message .= $content3;
$message .= "\r\n\r\n--" . $boundary . "--";
//invoke the PHP mail function
mail($email, $subject, $message, $headers);
?>
$email and $content3 are set via SQL and are setting correctly the email forms and is well formatted.

send PHP mail with Content-Type: multipart/alternative

I am trying to send a multipart mail that contains both html and plain text. This is also one of the ways to get through spam filters and to allow more people to read the mail in case of not supporting HTML. After spending long hours googling, I have found some examples. I made my code, which sends the mail but it displays the text with the html tags, code, string etc.
<?php
$boundary=md5(uniqid(rand()));
$header .= "From:My Name<something#something.com>\n";
$header .= "Reply-To: something#something.com \n";
$header .= 'MIME-Version: 1.0'."\r\n";
$header .= 'Content-type: multipart/alternative;boundary=$boundary '."\n";
$adres = "something#gmail.com";
$subject = "subject";
$message = "This is multipart message using MIME\n";
$message .= "--" . $boundary . "\n";
$message .= "Content-type: text/plain;charset=iso-8859-1\n";
$message .= "Content-Transfer-Encoding: 7bit". "\n\n";
$message .= "Plain text version\n\n";
$message .="--" . $boundary . "\n";
$message .="Content-type: text/html;charset=iso-8859-1\n";
$message .= "Content-Transfer-Encoding: 7bit". "\n\n";
$message .="<html>
<body>
<center>
<b>HTML text version</b>
</center>
</body>
</html>\n\n";
$message .= "--" . $boundary . "--";
if(mail($adres, $subject, $message, $header))
{
print'message sent';
}
else
{
print'message was not sent';
}
?>
This is the result:
This is multipart message using MIME
--c071adfa945491cac7759a760ff8baeb
Content-type: text/plain;charset=iso-8859-1
Content-Transfer-Encoding: 7bit
Plain text version
--c071adfa945491cac7759a760ff8baeb
Content-type: text/html;charset=iso-8859-1
Content-Transfer-Encoding: 7bit
<html>
<body>
<center>
<b>HTML text version</b>
</center>
</body>
</html>
--c071adfa945491cac7759a760ff8baeb--
As you can see it displays the coding instead of the message alone. I have tried many solutions posted like:
adding/removing \r\n;
changing \r\n to \n;
changing content type from alternative to mixed;
I am learning PHP and all I know is all I have read and done so far. I have still much to learn so please if you could tell me where is the problem. I would be very thankful.Best regards.
The line:
$header .= 'Content-type: multipart/alternative;boundary=$boundary '."\n";
Has the wrong quotes, so $boundary won't be expanded. Change to:
$header .= "Content-type: multipart/alternative;boundary=$boundary\n";
And like I said in the comments, in the message headers and the content section headers you should be using \r\n as the line break since that's what is defined in the RFC. Most MTAs will allow simply \n, but some will choke on the message, and some spam filters will count every RFC violation as a point towards your spam score.
Using something like PHPMailer is a much better option because it formats everything perfectly by default, and abides by just about every single obscure, boring RFC.
I think you need quotes around the boundary string.
try this:
$header .= 'Content-type: multipart/alternative; boundary="' . $boundary . '"\r\n';
Try this example https://github.com/breakermind/PhpMimeParser/blob/master/PhpMimeClient_class.php
$m = new PhpMimeClient();
// Add to
$m->addTo("email#star.ccc", "Albercik");
$m->addTo("adela#music.com", "Adela");
// Add Cc
$m->addCc("zonk#email.au");
// Add Bcc
$m->addBcc("boos#domain.com", "BOSS");
// Add files inline
$m->addFile('photo.jpg',"zenek123");
// Add file
$m->addFile('sun.png');
// create mime
$m->createMime("Witaj!",'<h1>Witaj jak się masz? <img src="cid:zenek123"> </h1>',"Wesołych świąt życzę!","Heniek Wielki", "hohoho#domain.com");
// get mime
// $m->getMime();
// Show mime
echo nl2br(htmlentities($m->getMime()));
Here is the complete script without errors:
<?php
error_reporting(-1);
ini_set("display_errors", "1");
$mailto = "email#enter-domainname-here.com";
$subject = "subject";
$boundary=md5(uniqid(rand()));
$header = "From:Info<".$mailto.">\n";
$header .= "Reply-To: ".$mailto."\n";
$header .= "MIME-Version: 1.0"."\n";
$header .= "Content-type: multipart/alternative; boundary=\"----=_NextPart_" . $boundary . "\"";
$message = "This is multipart message using MIME\n";
$message .= "------=_NextPart_" . $boundary . "\n";
$message .= "Content-Type: text/plain; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 7bit". "\n\n";
$message .= "Plain text version\n\n";
$message .="------=_NextPart_" . $boundary . "\n";
$message .="Content-Type: text/html; charset=UTF-8\n";
$message .= "Content-Transfer-Encoding: 7bit". "\n\n";
$message .="<html>
<body>
<center>
<b>HTML text version</b>
</center>
</body>
</html>\n\n";
$message .= "------=_NextPart_" . $boundary . "--";
if(#mail($mailto, $subject, $message, $header))
{
print'message sent';
}
else
{
print"message was not sent";
}
?>

How to customize the way an email looks sent from a php mail() script

So I can't seem to word the question right - but I would like to know how would you go about changing the way this
$Body = "";
$Body .= "Name: ";
$Body .= $Name;
$Body .= "\n";
$Body .= "City: ";
$Body .= $City;
$Body .= "\n";
$Body .= "Email: ";
$Body .= $Email;
$Body .= "\n";
$Body .= "Message: ";
$Body .= $Message;
$Body .= "\n";
looks when it reaches my e-mail. When I receive the e-mail (using it as a contact form), I get this ->
Name: lloan
City: SomeCity
Email: some#email.com
Message: Testing
I tried <strong> $Body .= "Name: ";</strong> and that didn't work - I also tried it as $Body .= "<strong> Name: </strong>"; and again, nothing. Can anyone point me in the right direction? I really want to learn how to do this - I've googled it a couple of times, but I think it's the way I'm wording my question that's not helping me.
EDIT: So I'm able to do this now - $Body .= "<strong>Name: </strong>"; using the suggestions below of adding the headers and then adding that to the mail() function - however, how do I go about using it on a bigger scale? For example - What if I want to have a colored background or what not - Am I also able to use CSS in this kind of situation? The other questions on SO do not answer this in it's entirety.
Here's how:
$to = 'yourmailtarget#example.com';
$subject = 'Your email subject';
$headers = "From: abc#abc.com \r\n";
$headers .= "Reply-To: no-reply#abc.com \r\n";
$headers .= "CC: abc#abc.com\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
$message = 'Put your html message here<br>';
$message .= "<b>HTML feature is now enabled</b><br>";
$message .= "<table border="1"><tr><td>Hello</td><td>World</td></tr></table>";
$message .= "For the styling, you can use inline styling:<Br>";
$message .= "<span style='color:#FF0000;'>This is red color</span>";
mail($to,$subject,$message,$headers,$parameters);
The most important part to answer your question is this line:
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";
That tells the system to produce the email using the HTML format.
Hope this helps
In the mail function add a parameter headers like this :
$headers = 'MIME-Version: 1.0' . "\r\n";
$headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
and call the mail function like this :
mail($to, $subject, $Body, $headers)
If you would like to format your message (the content of variable $Body), you are free to use as much HTML as you want.
If you want to send HTML email you also need to send a text-only version as not all mail clients support HTML, and some mail systems specifically strip HTML versions.
This means you need a Content-type:multipart header, and multiple sections with their own headers, each delimited by a specific boundary. The actual format is quote complex, so use a library like swiftmail or PHPMailer

PHP mail function - attachment coming as text

I know there are lot posts related to PHP mail function. But seriously i couldn't figure out what's wrong with my code below:
$subject = "New article submitted.";
$message = "You've received this e-mail through your website's write an article form: \n";
$message .= "Name: {$data['username']} \n";
$message .= "E-mail: {$data['email']} \n";
$message .= "\nRegards,\nAakriti \n";
$headers = "From: {$data['name']} <{$data['email']}> \n";
// Boundary
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
// Add the headers for a file attachment
$headers .= "\nMIME-Version: 1.0\n" .
"Content-Type: multipart/mixed;\n" .
" boundary=\"{$mime_boundary}\"";
// Add a multipart boundary above the plain message
$message = "This is a multi-part message in MIME format.\n\n" .
"--{$mime_boundary}\n" .
"Content-Type: text/plain;\n charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
$message . "\n\n" .
"--{$mime_boundary}\n";
// preparing attachments
for($i=0;$i < count($_FILES['articledata']['name']); $i++) {
// store the file information to variables for easier access
$tmp_name = $_FILES['articledata']['tmp_name'][$i];
$type = $_FILES['articledata']['type'][$i];
$name = $_FILES['articledata']['name'][$i];
$size = $_FILES['articledata']['size'][$i];
$file = fopen($tmp_name,"rb");
$attachment = fread($file,filesize($tmp_name));
fclose($file);
$attachment = chunk_split(base64_encode($attachment));
print_r($attachment);
//$attachment = chunk_split(base64_encode(file_get_contents($tmp_name)));
$message .= "Content-Type: {$type};\n" .
" name=\"{$name}\"\n" .
"Content-Transfer-Encoding: base64\n" .
"Content-Disposition: attachment;\n" .
" filename=\"{$name}\"\n\n" .
$attachment . "\n" .
"--{$mime_boundary}\n";
$message .= "--\n\n";
}
$headers .= "Reply-To: <{$data['email']}>";
if (mail($recipient,$subject,$message,$headers)) {
echo "<p>Thank you! Your mail was successfully sent to the webmaster. Thank you for your time.</p>";
} else {
echo "<p>Sorry, there was an error and your mail was not sent. Please find an alternative method of contacting the webmaster.</p>";
}
It just doesn't work as intended. Attachment is comes out as some binary text. Take a look below:
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="==Multipart_Boundary_xf6a3dd3e1c0c1f9233b8c66ce2a73e3ex"Reply-To: <test03#gmail.com>
This is a multi-part message in MIME format.
--==Multipart_Boundary_xf6a3dd3e1c0c1f9233b8c66ce2a73e3ex
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
You've received this e-mail through your website's write an article form:
Name: Johnson
E-mail: test#gmail.com
Regards,
Aakriti
--==Multipart_Boundary_xf6a3dd3e1c0c1f9233b8c66ce2a73e3ex
Content-Type: image/jpeg;
name="599307_322143481199958_2058932593_n.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="599307_322143481199958_2058932593_n.jpg"
/9j/4AAQSkZJRgABAgAAAQABAAD//gAEKgD/4gIcSUNDX1BST0ZJTEUAAQEAAAIMbGNtcwIQAABt
bnRyUkdCIFhZWiAH3AABABkAAwApADlhY3NwQVBQTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
9tYAAQAAAADTLWxjbXMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAApkZXNjAAAA/AAAAF5jcHJ0AAABXAAAAAt3dHB0AAABaAAAABRia3B0AAABfAAAABRyWFla
AAABkAAAABRnWFlaAAABpAAAABRiWFlaAAABuAAAABRyVFJDAAABzAAAAEBnVFJDAAABzAAAAEBi
VFJDAAABzAAAAEBkZXNjAAAAAAAAAANjMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAA
AEZCAABYWVogAAAAAAAA9tYAAQAAAADTLVhZWiAAAAAAAAADFgAAAzMAAAKkWFlaIAAAAAAAAG+i
AAA49QAAA5BYWVogAAAAAAAAYpkAALeFAAAY2lhZWiAAAAAAAAAkoAAAD4QAALbPY3VydgAAAAAA
AAAaAAAAywHJA2MFkghrC/YQPxVRGzQh8SmQMhg7kkYFUXdd7WtwegWJsZp8rGm/fdPD6TD////b
AEMABgQEBQQEBgUFBQYGBgcJDgkJCAgJEg0NCg4VEhYWFRIUFBcaIRwXGB8ZFBQdJx0fIiMlJSUW
HCksKCQrISQlJP/bAEMBBgYGCQgJEQkJESQYFBgkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQk
JCQkJCQkJCQkJCQkJCQkJCQkJCQkJP/CABEIAS8B4AMAIgABEQECEQH/xAAbAAACAwEBAQAAAAAA
AAAAAAAABQIDBAEGB//EABgBAQEBAQEAAAAAAAAAAAAAAAABAgME/8QAGAEBAQEBAQAAAAAAAAAA
AAAAAAECAwT/2gAMAwAAARECEQAAAfqgAAAHAPOabh2Vwm7+QWo06vqZa9w57WxTTLsFDRJ
UPDATE: Finally got it fixed after breaking my head for hours..
there were couple of problems:
As pointed out by asachanfbd mime
boundary was not properly nested.
This was one is silly & yet it was the main culprit - extra line breaks at below line of code:
$message .= "\nRegards,\nAakriti \n";
$headers = "From: {$data['name']} <{$data['email']}> \n";
Thanks everyone!
Not much of an answer to your question, but
you could have a look on PHPMailer and on its example.
It is pretty easy to add attachments with PHPMailer.
In a mail mime boundary is used to enclose different part of the mail. In your implementation you did not enclosed body of the mail in required mime type. Also keep in mind that mime boundary for the mail needs to be same for entire mail.
You can use these set of functions for easy implementation.
http://pastebin.com/AbZjzYdv

PHP mass mail script shows extra file in outlook

I use PHP script to send email with multiple attachments, it works great for gmail, but in Microsoft Outlook i also see blank file ATT00010.txt (random numbers.) as attachment. And when i send email from outlook with multiple attachments as well it does not show no file like this.
I echo'ed output from email script and there is no such file in code. Can someone tell me how to remove this file from outlook?
Email script is below.
// array with filenames to be sent as attachment
$files = array("file_1.ext","file_2.ext","file_3.ext",......);
// email fields: to, from, subject, and so on
$to = "mail#mail.com";
$from = "mail#mail.com";
$subject ="My subject";
$message = "My message";
$headers = "From: $from";
// boundary
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
// headers for attachment
$headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\"";
// multipart boundary
$message = "This is a multi-part message in MIME format.\n\n" . "--{$mime_boundary}\n" . "Content-Type: text/plain; charset=\"iso-8859-1\"\n" . "Content-Transfer-Encoding: 7bit\n\n" . $message . "\n\n";
$message .= "--{$mime_boundary}\n";
// preparing attachments
for($x=0;$x<count($files);$x++){
$file = fopen($files[$x],"rb");
$data = fread($file,filesize($files[$x]));
fclose($file);
$data = chunk_split(base64_encode($data));
$message .= "Content-Type: {\"application/octet-stream\"};\n" . " name=\"$files[$x]\"\n" .
"Content-Disposition: attachment;\n" . " filename=\"$files[$x]\"\n" .
"Content-Transfer-Encoding: base64\n\n" . $data . "\n\n";
$message .= "--{$mime_boundary}\n";
}
// send
$ok = #mail($to, $subject, $message, $headers);
if ($ok) {
echo "<p>mail sent to $to!</p>";
} else {
echo "<p>mail could not be sent!</p>";
}
If you want something that's a little less of a pain to use and send attachments with, try Swift Mailer. (swiftmailer.org) I've been using it in my projects and it works great.
Here's an example:
$message = Swift_Message::newInstance()
->setSubject('Webinar Registration')
->setFrom(array('replyto#example.org' => 'From Name'))
->setTo(array('destination#example.org'))
->setBody($MESSAGE_TEXT)
;
$message->attach(Swift_Attachment::fromPath('SOME_FILE_PATH'));
$transport = Swift_SmtpTransport::newInstance('127.0.0.1', 25);
$mailer = Swift_Mailer::newInstance($transport);
$result = $mailer->send($message);
Just my two cents.
Otherwise, I was going to mention what someone else already beat me to -- check the boundaries.
The last boundary line in a multipart/* message must have -- appended at the end, in addition to what all of the other boundary lines have. A consumer can use that to recognize the end of a message.
Apparently Outlook treats the absence of the correct ending as an indication that the message has been truncated, and then does the best it can to display whatever it did receive.
Its my second account, i actually found solution and don't need no library or class at all although i might turn this into class and add some stuff, its always better to have full understanding of process not just from, to, files etc fields.
Solution is simple here just replace last part with
if ($x == count($files)-1)
$message .= "--{$mime_boundary}--\r\n";
else
$message .= "--{$mime_boundary}\n";
\r is not necessary
if you just put -- it will use it many times inside loop IF checks if this is last loop.

Categories