I am trying to make a script to send emails and attach pdfs or other types of files later on.
I have been following various tutorials and have come to a dead end.
Can anyone see anything wrong with my code? I think i have just been looking at it for far too long.
<?php
include ("../../includes/auth.php");
$id = $_GET['id'];
$date = date('y-m-d h:i:s');
$recipient = $_GET['email'];
$lname = $_GET['lname'];
$fname = $_GET['fname'];
$subject ="Enquiry Form - $date";
//-------------attachment stuff----------
$fileatt = "/test.pdf";
$fileatttype = "application/pdf";
//$fileattname = "newname.pdf";
$file = fopen($fileatt, 'rb');
$data = fread($file, filesize($fileatt));
fclose($file);
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
//-------------------------------------
$headers = "From: test person <info#test.co.uk>";
$headers .= "\nMIME-Version: 1.0\n".
"Content-Type: multipart/mixed;\n".
" boundary=\"{$mime_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";
$data = chunk_split(base64_encode($data));
$message .= "–-{$mime_boundary}\n" .
"Content-Type: {$fileatttype};\n" .
" name=\"{$fileattname}\"\n" .
"Content-Disposition: attachment;\n" .
" filename=\"{$fileatt}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" ."--{$mime_boundary}--\n";
$message ."Dear ".$fname." ".$lname." Test message".$date;
echo $recipient."<br />";
echo $subject."<br />";
echo $message."<br />";
echo $headers."<br />";
mail($recipient, $subject, $message, $headers);
include ("../../includes/dbconn.php");
$set_datesent = "UPDATE _leads SET `Covering_letter_sent` = '$date' WHERE `ID` = '$id'";
//echo $set_datesent;
$result = mysql_query ($set_datesent, $connection)
or die ("Failed to perform query : $sql <br />".mysql_error());
?>
I would suggest you use something like the PEAR Mail library. Then sending an attachment becomes as easy and readable as the code below. You'll have to make sure the Mail library is installed, but this is a fairly simple task.
require_once('Mail.php');
require_once('Mail/mime.php');
$text = wordwrap($message, 70); // You'd put the text version of your message here as $message
$mime = new Mail_Mime();
$mime->setTXTBody($text);
$mime->setFrom($name . ' <' . $from_email . '>'); // The sender name and email ID go here
$mime->addAttachment($fpath, $ftype); // File path and type go here
$mime->setSubject($subject); // Subject goes here
$body = $mime->get()
$headers = $mime->headers();
$mail =& Mail::factory('mail');
$mail->send($to_email, $headers, $body); // The recipients email address goes here
unset($mime, $mail);
Additional things also become much easier this way, for example, writing a HTML mail.
I would highly recommend using a library like SwiftMailer. It's free and simplies your life by a lot.
I'd suggest Pear Mail_mime package (http://pear.php.net/package/Mail_Mime/). I once did attachment handling by hand, because i didn't know such library exists (stupid me) and when i figured it out, i immediately got rid of my poorly made script and started to use Mail_mime. It has few glitches, but heck, it's so much easier than code it by hand.
Related
I have been able to write php script (with HTML) to $_REQUEST online form data entry and either
(1) write to a CSV and email it as an attachment, or
(2) include data in the body of any email.
But I cannot do both at the same time. I want the CSV for quick import into database, and I want email body to also include the details so the shipping dept has a pick list for packing. How do I get both features to work simultaneously without interfering with each other?
Thank you in advance.
PHP SCRIPT
$to = "name#domain.com";
$subject = "Order - " . $_Tech_Name;
//Add the headers
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
$headers = "MIME-Version: 1.0\n" .
"From: {$email_from}\n" .
"Content-Type: multipart/mixed;\n" .
" boundary=\"{$mime_boundary}\"";
// email body includes only fields not null
$body = "";
foreach ($_REQUEST as $Field=>$Value) {
if($Value != ''){
$body .= "$Field: $Value\n\n";
}
}
$email_body = "Here are the details: \n\n $body";
// csv file name format
$today = date("m.d.y");
$csv_name = "order - " . $_Tech_Name . " " . $today . ".csv";
$fp = fopen($csv_name,'a');
fwrite($fp,$data);
fclose($fp);
$attachments[] = Array(
'data' => $data,
'name' => $csv_name,
'type' => 'application/vnd.ms-excel'
);
//Add sttachments
foreach($attachments as $attachment){
$data = chunk_split(base64_encode($attachment['data']));
$name = $attachment['name'];
$type = $attachment['type'];
$message .=
"--{$mime_boundary}\n" .
"Content-Type: {$type};\n" .
" name=\"{$name}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" ;
}
**PHP SCRIPT - I have isolated the problem with the following additional script that is part of the script shown above, but I do not as yet understand why it is a problem. By commenting out either $message (attachment) or $email_body (body only) I am able to get one or the other to work. But if I leave both variables in there, then neither works **
mail(
$to,
$subject,
$message, // for attachment only
// $email_body, // for body only
$headers
);
By isolating the problem in my original post I was able to get it to work by writing two (2) "mail" commands as follows:
// attachment
mail($to, $subject, $message, $headers);
// body
mail($to, $subject, $email_body, $headers);
I am happy with this solution, but if someone can find a way to get the same email to include the body content and attach a CSV, that would be ideal.
I've tried to follow the examples given in this forum, like the example given by freestate here - Error with PHP mail(): .
Below is my code copied from his revised example. It emails fine. And an attachment is shown in the email when received. However it cannot be opened and is always 125k in size.
I have verified that a file size is returned with "$file_size = filesize($file);". Also that the "fopen" does open the stream. In fact before I added the Multipart to the header, I could see the content in the body of the text (albeit not readable).
I'm only trying to attach a basic pdf file, on a window's platform (windows 10), Apache 2.4, PHP 5.6.16.0.
What would cause the attachment to fail to attach properly?
emailer('//serverName/path/', 'documentName.pdf');
function eMailer($path, $filename)
{
$eol = PHP_EOL;
$to = "xxxx#yyyyyyyy.com";
$subject = "File Name: ".$filename;
$body = "The this the written content of the body";
$file = $path.$filename;
$file_size = filesize($file);
$handle = fopen($file, "r");
$content = fread($handle, $file_size);
fclose($handle);
$content = chunk_split(base64_encode($content));
$uid = md5(uniqid(time()));
$header = "From: NameOfPerson <their#emailAddress.com>".$eol.
"MIME-Version: 1.0\r\n".
"Content-Type: multipart/mixed; boundary=\"".$uid."\"";
$message = "--".$uid.$eol.
"Content-Type: text/html; charset=ISO-8859-1".$eol.
"Content-Transfer-Encoding: 8bit".$eol.$eol.
$body.$eol.
"--".$uid.$eol.
"Content-Type: application/pdf; name=\"".$filename."\"".$eol.
"Content-Transfer-Encoding: base64".$eol.
"Content-Disposition: attachment; filename=\"".$filename."\"".$eol.
$content.$eol.
"--".$uid."--";
echo (mail($to, $subject, $message, $header))?'success':'failure';
}
So after spending considerable time trying to solve the attachment problem by myself, I decided to use one of the two common packages out there PHPMailer and Swiftmailer. Both seemed pretty good. I work on just one enterprise project and I do not have Composer installed. So I wanted something easy to download and plug into my project manually. After reading the installation instructions for swiftmailer, I decided this would be easy for me to install and use.
These are the steps I took
I downloaded the Swiftmailer zip file from Github
From the unzipped file I copied the "lib" folder right into my project "C:\myproject\lib"
Then I read the usage instructions in the online manual
To use it in my project all I needed to do was include it in my code like this:
function eMailer($path, $filename, $mailto, $subject, $message, $user)
{
$file = $path.$filename;
require_once 'C:\myProject\lib\swift_required.php';
// Create the SMTP configuration
$transport = Swift_SmtpTransport::newInstance("mymail_server_address ie: 192.111.22.33", 25);
$transport->setUsername($user['email']);
$transport->setPassword($user['password']);
// Create the mail transport configuration
$transport = Swift_MailTransport::newInstance();
// Create the message
$message = Swift_Message::newInstance();
$message->setTo(array(
$mailto['email']=> $mailto['name']
));
$message->setSubject($subject);
$message->setBody($message);
$message->setFrom($user['email'], $user['name']);
$message->attach(Swift_Attachment::fromPath($file));
// Send the email
$mailer = Swift_Mailer::newInstance($transport);
$mailer->send($message);
}
This obviously has much more capabilities than I need right now, but if in the future I need a mailer function in another part of my project it's there ready for me to use.
Try below code:
$name = "Name";
$email = "Email Address";
$to = "$name <$email>";
$from = "XYZ";
$subject = "TEST SUBJECT";
$mainMessage = "Hi, here's the file.";
$fileatt = "./test.pdf";
$fileatttype = "application/pdf";
$fileattname = "newname.pdf";
$headers = "From: $from";
// File
$file = fopen ( $fileatt, 'rb' );
$data = fread ( $file, filesize ( $fileatt ) );
fclose ( $file );
// Attach the file
$semi_rand = md5 ( time () );
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
$headers .= "\nMIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_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" . $mainMessage . "\n\n";
$data = chunk_split ( base64_encode ( $data ) );
$message .= "--{$mime_boundary}\n" . "Content-Type: {$fileatttype};\n" . " name=\"{$fileattname}\"\n" . "Content-Disposition: attachment;\n" . " filename=\"{$fileattname}\"\n" . "Content-Transfer-Encoding: base64\n\n" . $data . "\n\n" . "-{$mime_boundary}-\n";
// Send Email
if (mail ( $to, $subject, $message, $headers )) {
echo "The email was sent.";
} else {
echo "There was an error sending the mail.";
}
How come this piece of php code doesn't work with multiple recipient ?
It only works if $to has only one adress, like:
$to = 'aa#bb.com';
Edit
It works if email adresses are on the same domain.. For instance, if the website is www.example.com, emails such as xxx#example.com will work but yyy#other.com won't.
Solution
PHPMailer. It gives an easy way to configure SMTP.
Here is the initial code
<?php
//define the receiver of the email
$to = 'aa#bb.com, cc#dd.com, ee#ff.com';
// array with filenames to be sent as attachment
$files = array("a.zip","b.c","a.html");
// email fields: to, from, subject, and so on
$from = "mail#mail.com";
$subject ="My subject";
$message = "My message";
// boundary
$semi_rand = md5(time());
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
// headers for attachment
$headers = "From: $from";
$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>";
}
?>
Here is the final code
// PHPMailer
$mail = new PHPMailer;
// setting up PHPMailer
$mail->isSMTP();
$mail->Host = 'host.com';
$mail->SMTPAuth = false;
$mail->Port = xx;
$mail->setFrom($_POST['email'], $_POST['name']);
$mail->Subject = $_POST['subject'];
$mail->msgHTML($_POST['message']);
foreach($contacts as $contact)
$mail->addAddress($contact['email']);
// If the user has attached some files
foreach ($_FILES as $file)
$mail->addAttachment($file['tmp_name'], basename($file['name']));
$response = array("status" => $mail->send() ? "sent" : "error");
echo json_encode($response);
You need use proper RFC 2822 formating.
Don't use # because you don't know what is the error. If you format mails in format "user#example.com, anotheruser#example.com" it's correct and you need search problem elsewhere.
You can also see example #4 on http://php.net/manual/en/function.mail.php#example-3493 page.
although this is not a direct response to your issue, you could potentially save yourself trouble by using a pre-existing email sending library like either:
phpmailer
https://github.com/PHPMailer/PHPMailer
or simplesmtp
https://bitbucket.org/ghorwood/simplesmtp/
can anyone give me some idea how to attach a file from the server and send it as attachment through email??
i have the following code:
<?php
// Read POST request params into global vars
$to = $_POST['to'];
$from = $_POST['from'];
$subject = $_POST['subject'];
$message = $_POST['message'];
// Obtain file upload vars
$fileatt = $_FILES['fileatt']['tmp_name'];
$fileatt_type = $_FILES['fileatt']['type'];
$fileatt_name = $_FILES['fileatt']['name'];
$headers = "From: $from";
if (is_uploaded_file($fileatt)) {
// Read the file to be attached ('rb' = read binary)
$file = fopen($fileatt,'rb');
$data = fread($file,filesize($fileatt));
fclose($file);
// Generate a boundary string
$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; charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
$message . "\n\n";
// Base64 encode the file data
// Add file attachment to the message
$message .= "--{$mime_boundary}\n" .
"Content-Type: {$fileatt_type};\n" .
" name=\"{$fileatt_name}\"\n" .
//"Content-Disposition: attachment;\n" .
//" filename=\"{$fileatt_name}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" . "--{$mime_boundary}--\n";
}
// Send the message
$ok = #mail($to, $subject, $message, $headers);
if ($ok) {
echo "<p>Mail sent! Yay PHP!</p>";
} else {
echo "<p>Mail could not be sent. Sorry!</p>";
}
?>
but this code does not attach file from the server.
please help me out.. thanks in advance..!!
One question: Do you want to send e-mails with attachment or do you want to improve your PHP skills with this problem?
If you only want to send mails, have a look at PHPMailer which is very good and easily to handle. For myself I'm using this for years without problems.
For improving your skills: You say that the attachment is encoded in base64, but I cannot find the line where you do something like $data = base64_encode($data); You add the $data of your attachment in plain to the mail.
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.