通过 PHP 通过电子邮件发送动态创建的 PDF
Posted
技术标签:
【中文标题】通过 PHP 通过电子邮件发送动态创建的 PDF【英文标题】:Emailing A Dynamically Created PDF Through PHP 【发布时间】:2011-04-01 07:31:51 【问题描述】:我最近创建了一个在线模板,用于为我们的网站创建招聘信息。一切都完成了,它在浏览器中正确格式化,自动发布到我们的网站,bla bla bla。
我正在创建的最后一个部分是为管理员提供一些选项,以便以一致、方便的方式将帖子分发到各个地方(通过电子邮件)。我创建了一个 php 页面,使用 TCPDF 库动态创建 PDF 文档。加载 pdf.php?id=X 时,页面会显示一个包含职位发布 X 内容的 PDF。这意味着我从不将 PDF 文件保存到服务器,而是在每次调用时动态创建它。
但我想将此 PDF 附加到电子邮件中,并将其发送到各个大学和内部邮件列表等。如果我将 pdf.php?id=x 附加到电子邮件中,它不会附加 PDF ,它附加了一个看似空白的文件,名称为上述。
是否可以将其附加到电子邮件而不将其保存到服务器?
以下是根据 JM4 的回复添加的,以便进一步排除故障。我已将 PDF 文件创建放入一个函数中,并将其放入一个包含文件中,只是为了让事情更易于管理。
// random hash necessary to send mixed content
$separator = md5(time());
$eol = PHP_EOL;
// attachment name
$filename = "_Desiredfilename.pdf";
include_once('pdf.php');
// encode data (puts attachment in proper format)
$pdfdoc = job_posting_to_pdf($posting_id);
$attachment = chunk_split(base64_encode($pdfdoc));
///////////HEADERS INFORMATION////////////
// main header (multipart mandatory) message
$headers = "From: Sender_Name<valid_email@mydomain.com>".$eol;
//$headers .= "Bcc: email@domain.com".$eol;
$headers .= "MIME-Version: 1.0".$eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"".$separator."\"".$eol.$eol;
$headers .= "Content-Transfer-Encoding: 7bit".$eol;
$headers .= "This is a MIME encoded message.".$eol.$eol;
// message
$headers .= "--".$separator.$eol;
$headers .= "Content-Type: text/html; charset=\"iso-8859-1\"".$eol;
$headers .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$headers .= $message.$eol.$eol;
// attachment
$headers .= "--".$separator.$eol;
$headers .= "Content-Type: application/octet-stream; name=\"".$filename."\"".$eol;
$headers .= "Content-Transfer-Encoding: base64".$eol;
$headers .= "Content-Disposition: attachment".$eol.$eol;
$headers .= $attachment.$eol.$eol;
$headers .= "--".$separator."--";
//Email message
if(mail('valid_email@mydomain.com', 'test job posting', 'message body goes here', $headers))
echo 'mail sent';
else
echo 'error in email';
这是 pdf.php 的精简版:
function job_posting_to_pdf($job_id)
require_once(ROOT . 'assets/libs/tcpdf/config/lang/eng.php');
require_once(ROOT . 'assets/libs/tcpdf/tcpdf.php');
// create new PDF document
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
// set document information
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('');
$pdf->SetTitle('OPL Job Posting');
$pdf->SetSubject('Job Posting');
$pdf->SetKeywords('TCPDF, PDF, example, test, guide');
// remove default header/footer
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
//set margins
$pdf->SetMargins(11, PDF_MARGIN_TOP, 11);
//set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
//set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
//set some language-dependent strings
$pdf->setLanguageArray($l);
// ---------------------------------------------------------
$pdf->SetFont('times', 'I', 9);
$pdf->AddPage();
$left_cell_width = 60;
$row_height = 6;
$pdf->Image(ROOT . 'assets/gfx/logos/OPL-Logo.jpg', 0, 5, null, 16, null, null, 'N', false, null,'R');
$pdf->Ln('3');
if(!$row['internal'])
$pdf->Cell(0,0,'This position will be posted internally and externally, concurrently.',0,2,'C');
else
$pdf->Cell(0,0,'Internal posting only.',0,2,'C');
//Remainder of actual PDF creation removed to keep things simple
return $pdf->Output("", "S");
【问题讨论】:
向我们展示代码(或者最好是一个非常精简的骨架)。听起来您将 URL 转换为文件附件的方法是错误的。你为什么这么担心暂时不写文件? api.joomla.org/com-tecnick-tcpdf/TCPDF.html#methodOutput 我正在使用 'I' 选项作为 dest。我想知道我是否应该使用 S 选项。 这里的任何答案对您有帮助吗? @Alex,不,我已经离开这个项目好几年了。我相信我只是将它存储到临时文件夹然后附加它。 在此期间我自己管理了它,不过感谢您的回复;) 【参考方案1】:如果我完全理解你在问什么,这很简单。我假设您已经使用 fdpf 或 tcpdf 生成了 PDF。在这种情况下 - 只需使用以下代码:
<?php
// random hash necessary to send mixed content
$separator = md5(time());
$eol = PHP_EOL;
// attachment name
$filename = "_Desiredfilename.pdf";
// encode data (puts attachment in proper format)
$pdfdoc = $pdf->Output("", "S");
$attachment = chunk_split(base64_encode($pdfdoc));
///////////HEADERS INFORMATION////////////
// main header (multipart mandatory) message
$headers = "From: Sender_Name<sender@domain.com>".$eol;
$headers .= "Bcc: email@domain.com".$eol;
$headers .= "MIME-Version: 1.0".$eol;
$headers .= "Content-Type: multipart/mixed; boundary=\"".$separator."\"".$eol.$eol;
$headers .= "Content-Transfer-Encoding: 7bit".$eol;
$headers .= "This is a MIME encoded message.".$eol.$eol;
// message
$headers .= "--".$separator.$eol;
$headers .= "Content-Type: text/html; charset=\"iso-8859-1\"".$eol;
$headers .= "Content-Transfer-Encoding: 8bit".$eol.$eol;
$headers .= $message.$eol.$eol;
// attachment
$headers .= "--".$separator.$eol;
$headers .= "Content-Type: application/octet-stream; name=\"".$filename."\"".$eol;
$headers .= "Content-Transfer-Encoding: base64".$eol;
$headers .= "Content-Disposition: attachment".$eol.$eol;
$headers .= $attachment.$eol.$eol;
$headers .= "--".$separator."--";
//Email message
mail($emailto, $emailsubject, $emailbody, $headers);
?>
【讨论】:
你的想法是对的。这里的一切都有效,但是当它到达实际发送电子邮件的线路时,它似乎无限期地挂起。没有错误,什么都没有。可以传入的标头是否有限制?这是超过 810,000 个字符(但它只是一页 PDF)。 @Cory - 我的脚本有效。如果它挂起,则说明您的 pdf 脚本有问题或不同。我已经将上述内容用于 100 页的 pdf,没有问题。可以传递的标头数量没有限制。在编辑中发布您的实际代码,以便我们查看。 感谢 JM4,我已在原帖的代码中添加。就像我说的,除了实际的 mail() 调用之外,它会做所有事情。所以我可以通过 echo 毫无问题地输出 $headers。 @Cory Dee - 所以您可以确认 PDF 已创建(运行输出,D 或 I)?您正在运行什么版本的 PHP,您的 php.ini 设置中的邮件客户端是什么? Apache/2.2.11 (Win32) PHP/5.2.8。 php.ini 中的邮件设置设置为正确的 IP 和端口(我可以发送其他电子邮件)。如果我用 $headers .= $attachment.$eol.$eol; 注释掉该行它将发送一封附有空白 pdf 的电子邮件。所以邮件工作正常。【参考方案2】:我只需要弄清楚这一点,到最后我的眼球肯定很痛......
1) 你需要将PHPMailer安装到php服务器上。
2) 在您的 TCPDF 脚本中包含 PHPmailer 类,如下所示(您的路径可能会有所不同):
require_once('../PHPMailer_v5.1/class.phpmailer.php');
3) 现在,在您的 pdf 代码之后,只需像这样与 PHPMailer 对话:
$filename = "custompdf_$name_$time.pdf";
$pdf->Output($filename, 'F'); // save the pdf under filename
$mail = new PHPMailer(); $mail->IsSMTP();
$mail->Host = "mail.yourhost.com";
$mail->SMTPAuth = true; // enable SMTP authentication
$mail->Port = 26; // set the SMTP port for the GMAIL server
$mail->Username = "user+yourhost.com"; // SMTP account username
$mail->Password = "topsecret"; // SMTP account password
$mail->From = "noreply@yourhost.com";
$mail->FromName = "Stack Overflower";
$mail->AddAddress( $email, $name ); // in this case the variable has been passed
$mail->AddCC( "person@somehost.net", "Johnny Person"); // in this case we just hard code it
$mail->SMTPDebug = 0; // use 2 for debugging the email send
$pdf_content = file_get_contents($filename);
$mail->WordWrap = 50;
$mail->AddStringAttachment($pdf_content, "custompdf_for_$name_$time.pdf", "base64", "application/pdf"); // note second item is name of emailed pdf
$mail->IsHTML(true);
$mail->Subject = "Your pdf is here";
$mail->Body = "Dear $name,<br>
Here is your custom generated pdf generated at $t.<br><br>
Thank you";
if(!$mail->Send())
echo "Sorry ... EMAIL FAILED";
else echo "Done. . . Email sent to $email at $t.";
unlink($filename); // this will delete the file off of server
当然,对于发送的电子邮件,您有很多选择,例如不使用 html,或者同时发送 html 和文本,添加许多收件人和/或抄送等。
编辑:这确实将文件临时保存在服务器上,但它会使用 unlink 命令自行清理。
【讨论】:
您的解决方案意味着他需要将 PHP Mailer 脚本上传到他的目录,但事实并非如此。简单的 PHP Mail() 命令将发送电子邮件。你也不需要像你暗示的那样保存PDF文件,它就像 $pdf->Output($filename, 'S'); 谢谢-实际上,虽然邮件可以工作,但 phpmailer 更好,即我需要经过身份验证的 SMTP 功能。我想“S”选项会将临时工作保留在内存中,而不是作为磁盘上的实际文件......如果你能提供一个工作示例......我遇到了打开流错误失败。【参考方案3】:看看这个讨论 PHP 高级电子邮件的页面。
http://articles.sitepoint.com/article/advanced-email-php/5
他们获取上传的文件并将二进制数据加载到 $data 中,但您可以从那里开始。
【讨论】:
【参考方案4】:您可能还想通过PEAR Mail_Mime 将其作为附件发送。它可以接受附件作为数据字符串。
RMail 包看起来也可以通过 stringAttachment 类执行相同的操作。你必须用谷歌搜索它,因为我是一个新用户,所以我一次只能发布一个链接。
【讨论】:
【参考方案5】:我同意使用邮件库来代替使用默认的 mail() 函数手动构建 mime 消息。 SwiftMailer 是另一个不错的开源 PHP 邮件库。这是sample code,用于将动态内容用作附件,而无需先将其保存到文件系统。
【讨论】:
【参考方案6】:您的标题似乎有点过时:
application/octet-stream
应该变成application/octetstream
Content-Disposition: attachment ..
应该变成Content-Disposition: attachment; filename="' . basename($filename) . '"
附件标题应如下所示:
// attachment
$headers .= "--".$separator.$eol;
$headers .= "Content-Type: application/octetstream;".$eol; //Fixed
$headers .= "Content-Transfer-Encoding: base64".$eol;
$headers .= 'Content-Disposition: attachment; filename="' . basename(filename).'"'.$eol;
$headers .= 'Content-ID: <' . basename($filename) . '>' . $eol . $eol //EOL X2 Before
$headers .= $attachment;
//Run the above in a loop for multiple attachments, after add the final line
$headers .= '--' . $separator . '--' . $eol;
这是从我的一个工作应用程序中获取的,如果你想看的话,这里是循环:
foreach ($this->attachments as $attachment)
if (file_exists($attachment['file']))
$handle = fopen($attachment['file'], 'r');
$content = fread($handle, filesize($attachment['file']));
fclose($handle);
$message .= '--' . $boundary . $this->newline;
$message .= 'Content-Type: application/octetstream' . $this->newline;
$message .= 'Content-Transfer-Encoding: base64' . $this->newline;
$message .= 'Content-Disposition: attachment; filename="' . basename($attachment['filename']) . '"' . $this->newline;
$message .= 'Content-ID: <' . basename($attachment['filename']) . '>' . $this->newline . $this->newline;
$message .= chunk_split(base64_encode($content));
$message .= '--' . $boundary . '--' . $this->newline;
【讨论】:
如果 pdf 在服务器上不存在,而是通过带有 tcpdf 的 url,你会怎么做?以上是关于通过 PHP 通过电子邮件发送动态创建的 PDF的主要内容,如果未能解决你的问题,请参考以下文章
关于如何使用从其电子表格的html表单接收的数据创建pdf并通过电子邮件发送pdf文件的Google应用程序脚本
使用 PHP 从动态输入字段中捕获数组值并通过电子邮件发送它们
使用 React/Nodejs 通过电子邮件发送生成的 PDF 文件