How to download file and immediately export as email attachment - php

I have a web app where users can click a button to download a PDF report.
My users requested that when the PDF is downloaded, it's immediately opened as an email attachment (sort of like when a mailto anchor is clicked).
Is this even possible? I was thinking maybe using js to generate an anchor tag behind-the-scenes but I read that mailto doesn't really support attachments.
If this matters, the PDF is generated server side using PHP mPDF set to download output mode.

mailto supports attachment if the file is available locally. You can use the attach parameter to specify that.
e.g. mailto:lastname.firstname#xxx.com?subject=Test&attach=C:\Documents%20and%20Settings\username\Desktop\foldername\file.extn
However, I'm unsure how you would use this in your code as users can download the file to any location on their machine. If it's of any use, the attach parameter supports shared drive locations if the user has appropriate access.

For this you have to separate process in two step.
Generate PDF on server in some directory using http://wkhtmltopdf.org/
Send generated pdf as part of email attachement using https://github.com/PHPMailer/PHPMailer
configure both the service will help you achieve your task.
Below is the sample code which will help you
//generate PDF file for bill and send it in email
public function sendInvoiceInEmail($register_no, $html_string, $guest_email_id)
{
//create mailer class
$mail = new PHPMailer;
//remove old invoice file if exist at public/doc
// here i have used my path you have to use your path
if(file_exists(__DIR__.'/../../public/docs/invoice.pdf')){
unlink(__DIR__.'/../../public/docs/invoice.pdf');
}
// You can pass a filename, a HTML string, an URL or an options array to the constructor
$pdf = new Pdf([
'commandOptions' => [
'useExec' => false,
'escapeArgs' => false,
'procOptions' => array(
// This will bypass the cmd.exe which seems to be recommended on Windows
'bypass_shell' => true,
// Also worth a try if you get unexplainable errors
'suppress_errors' => true,
),
],
]);
$globalOptions = array(
'no-outline'
);
$pdf->setOptions($globalOptions);
$pdf->addPage($html_string);
//for Windows in my system i have setup wkhtmltopdf here
$pdf->binary = '"C:/Program Files/wkhtmltopdf/bin/wkhtmltopdf.exe"';
// for linux when you will host you have to setp on linux abd comment windows path and uncomment below line
//$pdf->binary = '/home/username/wkhtmltox/bin/wkhtmltopdf';
if (!$pdf->saveAs(__DIR__.'/../../public/docs/invoice.pdf')) {
throw new Exception('Could not create PDF: '.$pdf->getError());
}
//now send email and attach invoice.pdf file from public/doc/invoice.pdf
//$mail->SMTPDebug = 3; // Enable verbose debug output
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = 'hostname'; // Specify main and backup SMTP servers
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = 'username'; // SMTP username
$mail->Password = 'password'; // SMTP password
$mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted
$mail->Port = 587; // TCP port to connect to
$mail->setFrom('from_email_address', 'From Name',FALSE);
$mail->addAddress('to_email_address'); // Add a recipient
$mail->addAttachment(__DIR__.'/../../public/docs/invoice.pdf'); // Add attachments
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = 'Subject';
$mail->Body = 'email message body';
$is_email_sent = false;
if(!$mail->send()) {
// echo 'Message could not be sent.';
// echo 'Mailer Error: ' . $mail->ErrorInfo;
$is_email_sent = false;
} else {
// echo 'Message has been sent';
$is_email_sent = true;
}
return true;
}

Related

PHPMailer + HTML2PDF: pdf invalid and pj

Good morning all ,
I would like to attach a PDF created following a form with HTML2PDF then send it with PHMailer.
Everything works, the email goes well, I managed to create the PDF by saving it on my hard drive.
But when I try to attach it to my email, the pdf is fine in pj but I can't open it.
enter image description here
It is the same size of my locally created pdf.
I followed the tutorial and wiki of the two libraries, well I think ^^
Here is my PHPMailer code:
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require './vendor/phpmailer/phpmailer/src/Exception.php';
require './vendor/phpmailer/phpmailer/src/PHPMailer.php';
require './vendor/phpmailer/phpmailer/src/SMTP.php';
require './vendor/autoload.php';
// Instantiation and passing `true` enables exceptions
$mail = new PHPMailer(true);
$mail->CharSet = 'UTF-8';
try {
//Server settings
$mail->SMTPDebug = 0; // Enable verbose debug output
$mail->isSMTP(); // Send using SMTP
$mail->Host = '******'; // Set the SMTP server to send through
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = '*****'; // SMTP username
$mail->Password = '*****'; // SMTP password
//$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
$mail->Port = ****; // TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
//Recipients
$mail->setFrom('****#****.com', '****');
$mail->addAddress($to); // Add a recipient
//$mail->addAddress('ellen#example.com'); // Name is optional
$mail->addReplyTo($shop_email, 'Votre magasin');
//$mail->addCC('cc#example.com');
$mail->addBCC($shop_email);
// Attachments
$mail->addStringAttachment($pdf_done, 'myPdf.pdf'); // Add attachments
//$mail->addAttachment('/tmp/image.jpg', 'new.jpg'); // Optional name
// Content
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = $subject;
$mail->Body = $message;
$mail->AltBody = strip_tags($message);
$mail->send();
echo '';
} catch (Exception $e) {
echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
}
?>
and here is the code for HTML2PDF:
ob_start();
// --> mon code HTML de creeation du PDF
$content = ob_get_clean();
require_once dirname(__FILE__).'/../vendor/autoload.php';
use Spipu\Html2Pdf\Html2Pdf;
use Spipu\Html2Pdf\Exception\Html2PdfException;
use Spipu\Html2Pdf\Exception\ExceptionFormatter;
try{
$pdf = new \Spipu\Html2Pdf\Html2Pdf('P', 'A4', 'fr');
$pdf->writeHTML($content);
$pdf_done = $pdf->output('myPdf.pdf', 'S');
}catch(\Spipu\Html2Pdf\Exception\Html2PdfException $e){
die($e);
}
?>
I tried adding ", 'base64', 'application / pdf'" in the addStringAttachment but it doesn't change anything.
Do you have any idea of my mistake?
Thank you all
Debug one thing at a time. First download the PDF manually and make sure it looks correct – if the PDF is bad to start with, emailing it isn't going to improve things. Next check that it is readable from PHP – for example serve it using readfile(). Then when you try to attach it, check the return value of your call to addAttachment() like this:
if (!$mail->addAttachment('/path/to/myPdf.pdf')) {
die('could not read PDF');
}
Also note the difference between addAttachment and addStringAttachment; you're adding a file that's been saved to disk, so you want the first one, not the second.

PHPMailer not running on Windows10

First, I already read this stack post, and it doesn't seem to answer my question. I'm unclear how to apply those findings to my situation.
The following code works fine on my LAMP server (Bluehost), and I receive the email:
require_once("PHPMailer/src/Exception.php");
require_once("PHPMailer/src/PHPMailer.php");
require_once("PHPMailer/src/SMTP.php");
$mail = new PHPMailer\PHPMailer\PHPMailer();
$mail->SMTPDebug = 2; // verbose debug output
//$mail->SMTPDebug = 0; // no output
$mail->isSMTP();
$mail->SMTPAuth = true;
$mail->SMTPSecure = "ssl";
$mail->Host = "smtp.gmail.com";
$mail->Port = 465;
$mail->Username = $mailSender;
$mail->Password = $mailSenderPassword;
$mail->SetFrom($mailSender);
$mail->addAddress($mailTo);
$mail->isHTML(true);
$mail->Subject = "email test";
$mail->Body = "testing an email";
$mail->send();
But on my local WIMP (Windows-IIS-MySQL-PHP) PC, I always get the following error when running it:
Failed to connect to server: (0)
Note: I run php pages successfully all the time on my WIMP pc. The only thing that doesn't work locally is PHPMailer.
I tried turning my windows firewall completely off and that made no change.
How can I run this successfully on my Windows 10 IIS PC?
This was the solution:
My cafile set in php.ini had the wrong path to my cert:
openssl.cafile=wrongpath\cacert.pem
I fixed the path and everything worked.
As a stop-gap, failing everything else, the following will work:
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
)
);
Taken from here:
PHPMailer: SMTP Error: Could not connect to SMTP host
It sounds like your PHP is running just fine, as is PHPMailer — but you have some network problem that means that PHP can't talk to your mail server. PHP scripts that don't talk to mail servers obviously don't have any problem with that. Have a read of the PHPMailer troubleshooting guide which has some techniques for diagnosing network problems like this, though you may need to adapt them for Windows.
Since you're sending via gmail, I recommend that you base your code on the gmail example provided too — your code lacks any debug output or error handling, so you don't have any feedback on what's going wrong.
From first view I saw these, that you have written some props witout uppercases. That should be like:
IsSMTP()
AddAddress()
IsHTML()
Send()
Also I don't remember about this block much now, but before I've implemented something like this, and it worked. If it can help you, I'll share that code here (sending confirmation email):
use PHPMailer\PHPMailer\Exception as PhpMailerException;
use PHPMailer\PHPMailer\PHPMailer;
// ...
public function sendEmail_PhpMailer($to_email, $from_email, $name, $confirm_token): array
{
$mail = new PHPMailer(true); // Passing `true` enables exceptions
try {
//Server settings
// $mail->SMTPDebug = 2; // Enable verbose debug output
// $mail->isSMTP(); // Set mailer to use SMTP // https://github.com/PHPMailer/PHPMailer/issues/1209#issuecomment-338898794
$mail->Host = config('custom.phpmailer.host'); // Specify main and backup SMTP servers
$mail->SMTPAuth = true;
$mail->Username = config('custom.phpmailer.username'); // SMTP username
$mail->Password = config('custom.phpmailer.password'); // SMTP password
$mail->SMTPSecure = config('custom.phpmailer.secure'); // Enable TLS encryption, `ssl` also accepted
$mail->Port = config('custom.phpmailer.port'); // TCP port to connect to
$mail->setFrom($from_email, config('app.name'));
$mail->addAddress($to_email, $name);
// $mail->addReplyTo($from_email, config('app.name'));
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = 'Confirm Your Registration!';
$mail->Body = "<b>Click here to confirm your " . config('app.name') . " account!</b>";
$mail->AltBody = "Confirm your account with this link: " . route('web.email_confirm', $confirm_token);
$mail->send();
return [
'error' => false,
'message' => 'Message successfully sent!',
];
}
catch (PhpMailerException $e) {
return [
'error' => true,
'message' => 'Something went wrong: ', $mail->ErrorInfo,
];
}
}

php mailer sends 2 copies

I am sending a report by calling this PHP page daily on my browser. It (too often) sends emails twice (even if I make sure to open a new tab each time).
What's wrong with the code + How can I prevent it?
Here is the code:
<?php
require ("/home/phpmailer/PHPMailer-master/PHPMailerAutoload.php");
$mail = new PHPMailer;
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = 'localhost'; // Specify main and backup SMTP servers
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = 'USERNAME#DOMAIN.com'; // SMTP username
$mail->Password = 'PASSWORD'; // SMTP password
$mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted
$mail->Port = 587; // TCP port to connect to
$mail->From = 'FROM-NAME#DOMAIN.com';
$mail->FromName = 'FROM NAME';
$mail->ClearAddresses();
$mail->addAddress('email1#ABC.com', 'CLARA'); // Add a recipient
$mail->addCC('email##ABC.com', 'TOM'); // Add a CC recipient
$mail->addReplyTo('email2#ABC.com', 'Info');
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = 'EMAIL SUBJECT TITLE';
$mail->Body = file_get_contents('http://ADDRESS-OF-THE-FILE.PHP');
if(!$mail->send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message has been sent';
$mail->ClearAddresses();
}
?>
Do as SmartyCoder suggested in the comments.
If you are certain you're the only one hitting it, you might try something quick and dirty with cookies to track, like:
// See if a cookie is set, and if so, compare it to today
// If cookie value == today, die() - stop executing
if ( isset( $_COOKIE['email_reports_lastsent'] ) &&
$_COOKIE['email_reports_lastsent'] == date('Y-m-d') ) die();
// Set the cookie as today's date
setcookie( 'email_reports_lastsent', date('Y-m-d') );
This does NOT solve any issue if other devices/users are hitting your script. It also requires you to be using the same browser to send, and you cannot use Incognito or other private browsing tab.
I am going to guess that you are using Google Chrome and "Prefetch resources to load pages more quickly" is enabled. Essentially Chrome is fetching the URL before you finish typing so when you finish typing and hit enter then you are requesting it again.
Either turn off prefetching or save the URL to a bookmark and click the bookmark when you need to run the task.

PHP - Dompdf and PHPMailer unexpected behavior

I am working on a web application using PHP as a server-side and a jQuery framework as a client-side.
One of the scenarios of the application is to send an email with pdf file attached I am doing this using PHPMailer and Dompdf libraries.
I had created a function named sendMail in a file name send.php accept 4 params (receiver email,subject,data,email number) the last param is because I have 5 different emails may be sent depending on the situation and data param is the data will be rendered in the html email body.
The problem is when I call the function from send.php it work as expected the email sent and pdf file created and attached to the email .
but when I require send.php in any other file and call sendMail function I get the email only without any pdf file and the file not even generated or saved on the server.
send.php
<?php
require_once 'dompdf/autoload.inc.php';
// reference the Dompdf namespace
use Dompdf\Dompdf;
require 'PHPMailerAutoload.php';
$body = "test message";
sendMail('peter#w34.co','MLS mail',$body,5);
function sendMail($email,$subject,$body,$index){
$mail = new PHPMailer;
$mail->IsSMTP(); // telling the class to use SMTP
$mail->SMTPDebug = 1; // debugging: 1 = errors and messages, 2 = messages only
$mail->SMTPAuth = true; // SMTP authentication
$mail->SMTPSecure = 'tls'; // secure transfer enabled REQUIRED for GMail
$mail->Host = "smtp.gmail.com"; // SMTP server
$mail->Port = 587; // SMTP Port
$mail->Username = "peterwilson.intake34#gmail.com"; // SMTP account username
$mail->Password = "Password"; // SMTP account password // TCP port to connect to
$mail->From = 'peter#example.com';
$mail->FromName = 'Wilson';
$mail->addAddress($email); // Add a recipient
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = $subject;
$mail->Body=$body;
// instantiate and use the dompdf class
$dompdf = new Dompdf();
$dompdf->loadHtml($body);
// Render the HTML as PDF
$dompdf->render();
$output = $dompdf->output();
$file_to_save= "../work-orderes/file.pdf";
file_put_contents($file_to_save, $output);
$mail->addAttachment('../work-orderes/file.pdf');
if(!$mail->send()) {
// echo $mail->ErrorInfo;
} else {
return 1;
}
}
?>
save.php
<?php
require("sendSmtp/send.php");
session_start();
$body = "Hello World!";
sendMail('peter#w34.co','MLS mail',$body,5);
?>
Any suggestions about why Dompdf not works when calling it from any other file ??
What I have tried
removing dompdf and reinstall the latest stable version from
here
cleaning all code and just leave sendMail function and calling it
try to write the code from the beginnig
I solved it finally!
after debugging I found that everything going fine till $output = $dompdf->output(); after that I get an error on save the file using $file_to_save= "../work-orderes/file.pdf";
this work properly when I call the function sendMail() from send.php but when I call it from another file I get an error regarding accessing the path.
The Answer here that I should use the absolute path not the relative one like below
$file_to_save= $_SERVER['DOCUMENT_ROOT']."\work-orderes/file.pdf";
now the file saved successfully and attached to the email like expected!

PHPMailer: Mass Emails - Send all variable messages at once, instead of individually

i'm currently trying to figure out the best way to do this.
The current system i've made sends email one by one and fills in the information for each entry as in the array, such as email, first name and last name.
The problem here is if i send alot of messages it takes forever to run through as it's calling a function everytime, instead i want it to send them all at once through one single function.
I know you can add multiple to's but then the body of the email won't send the correct information relative to each email. If anyone can help me with this i'd really appreciate it, as i've searched all over for a solution.
<?php
require '../phpmailer/PHPMailerAutoload.php';?>
<?php
/* Block List */
$blocklist = array('emailblocked#gmail.com', 'emailblocked2#gmail.com');
$emaillist = array(
array(
'Email'=>'example#gmail.com',
'First Name'=>'John',
'Last Name'=>'Doe'
),
array(
'Email'=>'example2#gmail.com',
'First Name'=>'Joe',
'Last Name'=>'Doe'
),
array(
'Email'=>'example3#gmail.com',
'First Name'=>'Jane',
'Last Name'=>'Doe'
),
);
foreach($emaillist as $emailkey){
if (in_array($emailkey['Email'], $blocklist)) {
echo 'Message has been been blocked for '.$emailkey['Email'].'<br>';
}else{
$mail = new PHPMailer;
// $mail->SMTPDebug = 3; // Enable verbose debug output
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = 'smtp.mandrillapp.com'; // Specify main and backup SMTP servers
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = 'username#example.com'; // SMTP username
$mail->Password = 'passwordgoeshere'; // SMTP password
$mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted
$mail->Port = 587; // TCP port to connect to
$mail->From = 'noreply#example.com';
$mail->FromName = 'Example';
$mail->addAddress($emailkey['Email'], $emailkey['First Name'].' '.$emailkey['Last Name']); // Add a recipient
$mail->addReplyTo('info#example.com', 'Information');
$mail->isHTML(true); // Set email format to HTML
$mail->Subject = $emailkey['First Name'].' '.$emailkey['Last Name'];
$emailtemp = file_get_contents('templates/temp-1.html');
$emailtempfilteremail = str_replace("[[email]]", $emailkey['Email'], $emailtemp);
$emailtempfilterfirstname = str_replace("[[firstname]]", $emailkey['First Name'], $emailtempfilteremail);
$emailtempfilterlastname = str_replace("[[lastname]]", $emailkey['Last Name'], $emailtempfilterfirstname);
$mail->Body = $emailtempfilterlastname;
$mail->AltBody = 'This is a spicy email!';
if(!$mail->send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message has been sent to '.$emailkey['Email'].'<br>';
}
$mail->ClearAllRecipients();
}
}
?>
Thank you
There's an example of how to send to a list from a database efficiently in the examples bundled with PHPMailer. There's nothing inherently likely to get you blacklisted by using PHPMailer for sending large volumes, but you do need to tread carefully. Mandrill isn't magic - it's as vulnerable as anything else to being blocked if you send spam through it.
If you want to send 50 simultaneously from PHP, fire up multiple processes with the pcntl extension, but it won't actually help you very much as you'll be increasing overhead enormously. You can set SMTPKeepAlive = true in PHPMailer which will reduce overhead a lot (it avoids making a new connection for every message), but it still won't send simultaneous messages - nothing will. There isn't an option in SMTP to send multiple messages with different bodies simultaneously on the same connection.
Sending to a big list during a page load in a browser is very unreliable; use a cron script or background process to do your actual sending and just set it up through your web interface. One tip if you are waiting for a page load - call ignore_user_abort() early on so that it won't stop sending if your browser closes the connection - and beware the page refresh! If you want to send much faster, install a local mail server like postfix and use that to relay - it will be far faster and more reliable than sending directly.
Yes, it is possible with a modification of your code, the problem is not with the PHPMailer itself, but with your approach. You should avoid using an new instance of the class inside a loop (this leads to memory exhaustion with large lists), instead, only invoke $mail->addAddress(...) or $mail->Subject(...) inside the foreach loop.
If you read the source code of the PHPMailer, you will notice how exactly the functions addAddress(), Subject() or Body() works.
Your code should look something like this:
<?php
/*Move your "generic" initialization outside the loop*/
$mail = new PHPMailer;
// $mail->SMTPDebug = 3; // Enable verbose debug output
$mail->isSMTP(); // Set mailer to use SMTP
$mail->Host = 'smtp.mandrillapp.com'; // Specify main and backup SMTP servers
$mail->SMTPAuth = true; // Enable SMTP authentication
$mail->Username = 'username#example.com'; // SMTP username
$mail->Password = 'passwordgoeshere'; // SMTP password
$mail->SMTPSecure = 'tls'; // Enable TLS encryption, `ssl` also accepted
$mail->Port = 587; // TCP port to connect to
$mail->From = 'noreply#example.com';
$mail->FromName = 'Bet Monkey';
$mail->isHTML(true); // Set email format to HTML
$mail->addReplyTo('info#example.com', 'Information');
$emailtemp = file_get_contents('templates/temp-1.html');
$mail->AltBody = 'This is a spicy email!';
/*Start the loop by adding email addresses*/
foreach($emaillist as $emailkey){
if (in_array($emailkey['Email'], $blocklist)) {
echo 'Message has been been blocked for '.$emailkey['Email'].'<br>';
}else{
$mail->addAddress($emailkey['Email'], $emailkey['First Name'].' '.$emailkey['Last Name']); // Add a recipient
$mail->Subject = $emailkey['First Name'].' '.$emailkey['Last Name'];
$emailtempfilteremail = str_replace("[[email]]", $emailkey['Email'], $emailtemp);
$emailtempfilterfirstname = str_replace("[[firstname]]", $emailkey['First Name'], $emailtempfilteremail);
$emailtempfilterlastname = str_replace("[[lastname]]", $emailkey['Last Name'], $emailtempfilterfirstname);
$mail->Body = $emailtempfilterlastname;
if(!$mail->send()) {
echo 'Message could not be sent.';
echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
echo 'Message has been sent to '.$emailkey['Email'].'<br>';
}
$mail->ClearAllRecipients();
}
}
Using the above approach I personally have send hundreds of thousands emails, but, as they say in the comments - you'll risking to be blacklisted (you can check here or here for details).

Categories