I am trying to write a PHP script that will generate a PDF and email it. My PDF generator works perfectly as an independent URL, but for some reason when I try to make the script email the generated PFD, the received file can't be opened. Here is the code:
include_once('Mail.php');
include_once('Mail/mime.php');
$attachment = "cache/form.pdf";
// vvv This line seems to be where the breakdowns is vvv
file_put_contents( $attachment, file_get_contents( "http://www.mydomain.com/generator.php?arg1=$arg1&arg2=$arg2" ) );
$message = new Mail_mime();
$message->setTXTBody( $msg );
$message->setHTMLBody( "<html><body>$msg</body></html>" );
$message->addAttachment( $attachment );
$body = $message->get();
$extraheaders = array( "From" => $from,
"Cc" => $cc,
"Subject" => $sbj );
$mail = Mail::factory("mail");
$headers = $message->headers( $extraheaders );
$to = array( "Jon Doe <jon#mydomain.com>",
"Jane Doe <jane#mydomain.com>" );
$addresses = implode( ",", $to );
if( $mail->send($addresses, $headers, $body) )
echo "<p class=\"success\">Successfully Sent</p>";
else
echo "<p class=\"error\">Message Failed</p>";
unlink( $attachment );
The line that I marked does generate a PDF file in the cache folder, but it will not open, so that seems to be a problem. However, when I try to attach a PDF file already exists, I have the same problem. I have tried $message->addAttachment( $attachment, "Application/pdf" ); as well, and it does not seem to make a difference.
Typically web server directories should have write permissions locked down. This is probably why you are experiencing problems with file_put_contents('cache/form.pdf').
// A working example: you should be able to cut and paste,
// assuming you are on linux.
$attachment = "/var/tmp/Magick++_tutorial.pdf";
file_put_contents($attachment, file_get_contents(
"http://www.imagemagick.org/Magick++/tutorial/Magick++_tutorial.pdf"));
Try changing where you are saving the pdf to a directory that allows write and read permissions to everyone. Also make sure this directory is not on your web server.
Also try changing the following three things
From
$message = new Mail_mime();
To
// you probably don't need this the default is
// $params['eol'] - Type of line end. Default is ""\r\n""
$message = new Mail_mime("\r\n");
From
$extraheaders = array(
"From" => $from,
"Cc" => $cc,
"Subject" => $sbj,
);
To
$extraheaders = array(
"From" => $from,
"Cc" => $cc,
"Subject" => $sbj,
'Content-Type' => 'text/html'
);
From
$message->addAttachment($attachment);
To
// the default second argument is $c_type = 'application/octet-stream'
$isAttached = $message->addAttachment($attachment, 'aplication/pdf');
if ($isAttached !== true) {
// an error occured
echo $isAttached->getMessage();
}
And you always want to make sure that you call
$message->get();
before
$message->headers($extraheaders);
or the whole thing wont work
I am pretty sure it must be an ini problem blocking file_get_contents(). However I came up with a better solution. I reworked the generator.php file and turned it in to a function definition. So I've got:
include_once('generator.php');
$attachment = "cache/form.pdf";
file_put_contents( $attachment, my_pdf_generator( $arg1, $arg2 ) );
...
$message->addAttachment( $attachment, "application/pdf" );
This way I do not need to write the file first. It works great (although I am still having slight issues with Outlook/Exchange Server, but I think that is a largely unrelated issue).
Related
What is the correct way to generate an email attachment with PhpWord?
I tried multiple ways but I get a corrupt file with size 1kb. If I trigger a download of the file instead, the file is OK.
$fileName = 'file.docx';
$fileAttachment = tempnam(sys_get_temp_dir(), 'PHPWord');
$template->saveAs($fileAttachment);
$contentType = "application/octet-stream";
$notification
->setTemplate("template", $templateParams)
->setSubject($this->_("Email subject"))
->addRecipient("to", $email, $email)
->addAttachment($fileName, $fileAttachment, $contentType);
What am I doing wrong?
Thank you!
You could try to use file_get_contents function to read the contents of the file and then pass it as the second parameter to the addAttachment() method:
$fileAttachmentContent = file_get_contents($fileAttachment);
$notification
->setTemplate("template", $templateParams)
->setSubject($this->_("Email subject"))
->addRecipient("to", $email, $email)
->addAttachment($fileName, $fileAttachmentContent, $contentType);
PHPWord is for generating Word documents, but it does not send mails.
You can combine it with any PHP mailer library. This is a sample on how to do it using SwitfMailer:
<?php
require_once '[...]/phpword/src/PhpWord/Autoloader.php';
require_once '[...]/swiftmailer/lib/swift_required.php';
// create a new document with phpWord
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
$text = $section->addText("Here your text...");
// Use Swift Mailer to create an attachment object...
$attachment = new Swift_Attachment(
$phpWord->save(),
'file.docx',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
);
// ...and send the email
$transport = Swift_SmtpTransport::newInstance('smtp.yoursmtp.com', 25);
$mailer = Swift_Mailer::newInstance($transport);
$message = Swift_Message::newInstance('Here your subject')
->setFrom(['sender#sdomain.net' => 'Sender Name'])
->setTo(['receiver#rdomain.org' => 'Receiver Name'])
->setBody('Here the body message...')
->attach($attachment);
$result = $mailer->send($message);
You can use any other mail library you like. Or even use the PHP mail() function, but is more tricky to set the mail headers properly.
i just ran into a problem, when sending mails with attachments larger than about 2.5Mb from a server. Sending emails with smaller attachments work, but as soon the critical size of about 2 or 2.5Mb is reached, the mail is not send anymore.
The PDF files and merged target PDF are created without problem, no matter of the size. But only smaller PDF files are send by mail. Not even an empty mail is send, when the attachments are too large.
The process is a follows:
1) The php script creates several PDF files.
2) Those files are merged through gs
$finCmd = 'gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile='.$pathDest.$pdfFilename.' input1.pdf input2.pdf input3.pdf';
// Create PDF
$execResult = exec($finCmd);
3) The email body is created
protected function setBodyHtmlpart($content, $pdfFilepath = null, $pdfFilename = null) {
$content="<p><span style='font-size:10.0pt;font-family:\"Arial\",\"sans-serif\";color:black;'>".$content.'</span></p>';
$html = new MimePart($content.$this->getSignature());
$html->type = "text/html";
$body = new MimeMessage();
if ($pdfFilename != '') {
$pdfAttach = new MimePart(file_get_contents($pdfFilepath.$pdfFilename));
$pdfAttach->type = 'application/pdf';
$pdfAttach->filename = $pdfFilename;
$pdfAttach->encoding = \Zend\Mime\Mime::ENCODING_BASE64;
$pdfAttach->disposition = \Zend\Mime\Mime::DISPOSITION_ATTACHMENT;
$body->setParts(array($html, $pdfAttach));
} else {
$body->setParts(array($html));
}
return $body;
}
4) The email is send with:
protected function send($fromAddress, $fromName, $toAddress, $toName, $subject, $bodyParts)
{
// setup SMTP options
$options = new SmtpOptions(array(
'name' => 'XServer',
'host' => 'xServer',
'port' => 25,
'connection_class' => 'plain',
'connection_config' => array(
'username' => 'Xusername',
'password' => 'Xpassword',
),
));
$mail = new Message();
$mail->setBody($bodyParts);
$mail->setFrom($fromAddress, $fromName);
$mail->setTo($toAddress, $toName);
$mail->setSubject($subject);
$transport = new SmtpTransport($options);
$transport->send($mail);
}
Any hints are welcome, as i am totaly lost.
I thought there could be race problem: exec is not finished, but script already tries to send the mail and cancels. But i than would at least receive an empty email.
Edit:
Changing then Mime\Mime::ENCODING_BASE64 delivers the mails, but PDF files are corrupted.
Have you tried using type Octetstream
$pdfAttach->type = Mime::TYPE_OCTETSTREAM;
$pdfAttach->encoding = Mime::ENCODING_BASE64;
It seems like, that the issue is the mime encoding.
All options:
Zend_Mime::ENCODING_7BIT: '7bit' --> corrupted file
Zend_Mime::ENCODING_8BIT: '8bit'; --> corrupted file
Zend_Mime::ENCODING_QUOTEDPRINTABLE: 'quoted-printable' --> corrupted
file
Zend_Mime::ENCODING_BASE64: 'base64' --> file not send
did not work.
Developed a solution with PHPMailer.
Worked out.
I am using wp_upload_bits which is a cURL wrapper for WordPress for saving in my server a remote .png image, which was previously downloaded with Content-Type: binary/octet-stream.
This is how my code looks like:
(wrong code, see the one underneath)
//File contents
$attachment = 'image/png,' . file_get_contents( $url );
// Upload bits attachment
$result = wp_upload_bits(
basename( $url ),
null,
$attachment
);
(right code)
$attachment = new WP_Http();
$attachment = $attachment->request( $url, array(
'headers' => array(
'X-app-action' => 'importing'
),
) );
// Upload bits attachment
$result = wp_upload_bits(
basename( $url ),
null,
$attachment[ 'body' ]
);
EDITED: This is actually the code, I got confused, I am using WP_Http() instead of file_get_contents()
Unfortunately, I have to assume that the image is being saved with the wrong format, since it looks kind of corrupted or broken, the image won't show up at all.
What am I doing wrong?
Mail_Mime 1.8.9
Mail 1.2.0
php 5.4.12
project = run from my localhost dev computer (LAN).
Hello, I am attempting to add an image to my email I am sending out using MailMime. The image never loads. I'll go through the steps below:
Here I am stripping everything off of the image but the image name and extension (ie:noimage.jpg). I then create a link for non image related purposes, I then create the image tag using the stripped image name and extension.
$url = substr($baseImage, 36);
$domainName = DomainNameUtil::getWebSiteDomainName();
$projectPath = DomainNameUtil::getPathToProject();
$productUrl = $domainName . $projectPath . "/client/app/#/products/" . $product->id;
$productLink = "<a href='$productUrl'>$product->name</a>";
$string = "<img src='$url' /><br />";
Here I am sending the message
$mailConfig = MailConfigurationUtil::getMailConfigurationData();
$headers = array (
'From' => $from,
'To' => $to,
'Subject' => $subject
);
$crlf = "\n";
$mime = new Mail_mime(array('eol' => $crlf));
$mime->setHTMLBody($body);
$headers = $mime->headers($headers);
$smtp = Mail::factory('smtp', array (
'host' => $mailConfig->mailServer,
'port' => $mailConfig->port,
'auth' => true,
'username' => $mailConfig->userName,
'password' => $mailConfig->password
));
$productManager = new ProductManager();
$ordersManager = new OrdersManager();
$orderVirtualItem = $ordersManager->getOrderVirtualItemByBoxId($boxId);
$product = $productManager->getProductById($orderVirtualItem->itemId);
$url = $product->baseImage;
$domain = DomainNameUtil::getWebSiteDomainName();
$path = DomainNameUtil::getPathToProject();
$r = substr($url, 5);
$finalUrl = $domain . $path . $r;
$mime->addHTMLImage(file_get_contents($finalUrl),'image/jpeg',basename("noimage"),false, "blackstone");
$body = $mime->get();
$mail = $smtp->send($to, $headers, $body);
In the example above, I know the image is called noimage.jpeg, so in the addHtmlImage above I simply stated the name. I am under the impression that the name used in addHtmlImage has to be the same name as the image name in the image src tag in the html body.
When I actually send my email I get the email and I get some text saying there is an image, but the image tag in my email body does not load.
Also, looking at it under firebug it has a proxy attached to the image src. Also it references it as PROXYADDRESS#http://noimage.jpg
Anyone have experience in this that can help me understand why the image is not loading?
For reference, I saw someone posting this method online and tried copying them. before this I had even tried putting the whole url in the image src and not adding the image to MIME, and it did not work.
i got pretty similar problem here.
What i got so far: it depends on phpversion (and installed Mail_Mime).
Mail_Mime seems to be "broken" under php 5.4.30
If i run my script under php 5.2.17 all images show up correctly
If i run my script under php 5.4.30 all images do not show up correctly
when i compare both sourcecodes, it seems, Mail_Mime under 5.4.30 gets messy with the order of boundarys and the Content-Type:
Content-Type: multipart/alternative; in 5.2.17
Content-Type: multipart/related; in 5.4.30enter image description here
When specifying a context-id (the last parameter to addHtmlImage()) you must reference the image in the html message correctly: <img src="cid:context-id#local" />. Of course replacing context id with your own context id for each image to show.
We have a growing mailing list which we want to send our newsletter to. At the moment we are sending around 1200 per day, but this will increase quite a bit. I've written a PHP script which runs every half hour to send email from a queue. The problem is that it is very slow (for example to send 106 emails took a total of 74.37 seconds). I had to increase the max execution time to 90 seconds to accomodate this as it was timing out constantly before. I've checked that the queries aren't at fault and it seems to be specifically the sending mail part which is taking so long.
As you can see below I'm using Mail::factory('mail', $params) and the email server is ALT-N Mdaemon pro for Windows hosted on another server. Also, while doing tests I found that none were being delivered to hotmail or yahoo addresses, not even being picked up as junk.
Does anyone have an idea why this might be happening?
foreach($leads as $k=>$lead){
$t1->start();
$job_data = $jobObj->get(array('id'=>$lead['job_id']));
$email = $emailObj->get($job_data['email_id']);
$message = new Mail_mime();
//$html = file_get_contents("1032.html");
//$message->setTXTBody($text);
$recipient_name = $lead['fname'] . ' ' . $lead['lname'];
if ($debug){
$email_address = DEBUG_EXPORT_EMAIL;
} else {
$email_address = $lead['email'];
}
// Get from job
$to = "$recipient_name <$email_address>";
//echo $to . " $email_address ".$lead['email']."<br>";
$message->setHTMLBody($email['content']);
$options = array();
$options['head_encoding'] = 'quoted-printable';
$options['text_encoding'] = 'quoted-printable';
$options['html_encoding'] = 'base64';
$options['html_charset'] = 'utf-8';
$options['text_charset'] = 'utf-8';
$body = $message->get($options);
// Get from email table
$extraheaders = array(
"From" => "Sender <sender#domain.com>",
"Subject" => $email['subject']
);
$headers = $message->headers($extraheaders);
$params = array();
$params["host"] = "mail.domain.com";
$params["port"] = 25;
$params["auth"] = false;
$params["timeout"] = null;
$params["debug"] = true;
$smtp = Mail::factory('mail', $params);
$mail = $smtp->send($to, $headers, $body);
if (PEAR::isError($mail)) {
$logObj->insert(array(
'type' => 'process_email',
'message' => 'PEAR Error: '.$mail->getMessage()
));
$failed++;
} else {
$successful++;
if (DEBUG) echo("<!-- Message successfully sent! -->");
// Delete from queue
$deleted = $queueObj->deleteById($lead['eq_id']);
if ($deleted){
// Add to history
$history_res = $ehObj->create(array(
'lead_id' => $lead['lead_id'],
'job_id' => $lead['job_id']
)
);
if (!$history_res){
$logObj->insert(array(
'type' => 'process_email',
'message' => 'Error: add to history failed'
));
}
} else {
$logObj->insert(array(
'type' => 'process_email',
'message' => 'Delete from queue failed'
));
}
}
$t1->stop();
}
hard to tell. You should profile your code using xdebug to pintpoint low hanging fruit.
Also I think you might consider using a message queue to process your e-mail(redis/beanstalkd/gearmand/kestrel) asynchronous or using third-party dependency like for example google app engine which is very cheap($0.0001 per recipient/first 1000 emails a day free)/reliable. That will cost you about 10 cent a day when considering your load.
you're facing a couple of different problems.
1.) to send a lot of emails you really need a mailer queue and several mail servers to get mail from that queue and process the mail in turn (round robin style <-- this link is related but not perfectly specific to your needs. [It's enough to get you started]).
2.) your mail is likely not getting to Hotmail/yahoo for one of 2 reasons.
a.) you don't have RDNS properly configured and when the look for your IP (from the heder) it is not mapping back right to your domain in the header. or
b.), you've already been flagged as a spammer on SPAMHAUS or whatever the blacklisting service du jour is.