views:

130

answers:

7

I've recently created an online template for creating job postings for our website. Everything is all done, it formats correctly in a browser, automatically posts to our website, bla bla bla.

The last piece I'm creating is to give the administrator a few options for distributing the posting to various places (via email) in a consistent, convenient way. I've created a PHP page that creates a PDF doc on the fly, using the TCPDF library. When loading pdf.php?id=X, the page displays a PDF with the content of job posting X. This means I'm never saving the PDF file to the server, just creating it on the fly each time it's called.

But I want to attach this PDF to an email, and send it to various colleges, and internal mailing lists, etc. If I attach the pdf.php?id=x to the email, it doesn't attach the PDF, it attaches what appears to be a blank file, with the above name.

Is it possible to attach this to the email without saving it to the server?


Below added based on JM4's response for further trouble shooting. I have put the PDF file creation into a function, and put it into an include file, just to keep things easier to manage.

// 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<[email protected]>".$eol;
//$headers .= "Bcc: [email protected]".$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('[email protected]', 'test job posting', 'message body goes here', $headers)) {
    echo 'mail sent';
} else {
    echo 'error in email';
}

Here is a stripped down version of 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");
}
A: 

Take a look at this page which discusses advanced email in PHP.

http://articles.sitepoint.com/article/advanced-email-php/5

They take an uploaded file and load the binary data into $data, but you can just start from there.

Fosco
A: 

You may also want to look at sending it as an attachment via PEAR Mail_Mime. It can accept an attachment as a string of data.

The RMail package also looks as if it will do the same via the stringAttachment class. You'll have to google for it, because I'm a new user and so I can post only one link at a time.

Craig
A: 

If I completely understand what you are asking this is quite simple. I am assuming you already have the PDF generated using something like fdpf or tcpdf. In that case - simply use the following code:

<?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<[email protected]>".$eol;
    $headers .= "Bcc: [email protected]".$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);

    ?>
JM4
You have the right idea. Everything here works, but when it gets to the line to actually send the email, it seems to hang indefinitely. No error, no nothing. Is there a limit to headers that can be passed in? This is a little over 810,000 chars (but it's just a one page PDF).
Cory Dee
@Cory - My script works. if it is hanging, there is something wrong or different about your pdf script. I have used the above for 100 page pdfs without issue.There is no limit to the number of headers than can be passed. Post your actual code in an edit so we can look.
JM4
Thanks JM4, I've added in the code in the original post.Like I said, it will do everything but the actual mail() call. So I can output $headers via echo with no probs.
Cory Dee
@Cory Dee - so you can confirm that the PDF is created however (running output, D or I)? What version of PHP are you running and what mail client in your php.ini settings?
JM4
Apache/2.2.11 (Win32) PHP/5.2.8. The mail settings in php.ini are set to the correct IP and port (I can send other emails). If I comment out the line with $headers .= $attachment.$eol.$eol; it will send an email with a blank pdf attached. So mail is working.
Cory Dee
Oh, and yes, it does generate a PDF file that can be loaded by a browser with no problems.
Cory Dee
800K is big in email terms. This sounds like a size limit problem. either sending or receiving.
Talvi Watia
@Talvi - 800k is the number of characters, not file size. Cory Dee - what happens when you change the last line in pdf.php to: return $pdf->Output("", "I");
JM4
A: 

I just had to figure this out and my eyeballs were definitely sore by the end...

1) You need to install PHPMailer to the php server.

2) Include the PHPmailer class in your TCPDF script, like so (your path may vary):

require_once('../PHPMailer_v5.1/class.phpmailer.php');

3) Now after your pdf code simply talk to PHPMailer like so:

$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 = "[email protected]";
$mail->FromName = "Stack Overflower";
$mail->AddAddress( $email, $name );  //  in this case the variable has been passed
$mail->AddCC( "[email protected]", "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

Of course you have many options for the email sent, like not using html, or sending both html and text, adding many recipients and/or cc's, etc.

EDIT: This does save the file temporarily on the server, but it cleans up after itself with the unlink command.

Mischa
@Mischa - Your solution implies he needs to upload the PHP Mailer scripts to his directory which is not the case. Simple PHP Mail() commands will send email. You also do not need to save the PDF file as you implicate, it works just fine as $pdf->Output($filename, 'S');
JM4
Thanks- Actually, while mail works, phpmailer is way better, i.e. I needed the authenticated SMTP functions. I suppose the 'S' option would keep the temp work in memory and not as an actual file on disk... if you can provide a working example... I got a failed to open stream error.
Mischa
A: 

I agree about using a mail library in place of building mime messages by hand with the default mail() function. SwiftMailer is another good open source PHP mail library. Here's the sample code for using dynamic content as an attachment without having to save it to the file system first.

Jeff Standen
A: 

Look, using those scripts it's very annoying and complicated. Use Zend_Mail and Zend_Pdf (see zend framework website) , you can write a much more maintainable and shorter code using few LOC and OOP approach.

Elvis
A: 

Your headers seem to be a little out:

  • application/octet-stream should become application/octetstream

  • Content-Disposition: attachment .. should become Content-Disposition: attachment; filename="' . basename($filename) . '"

heres what the attachement headers should look like:

// 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;

This was taken from one of my working applications, heres the loop if you wish to see it:

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; 
RobertPitt