Solved

PHPMailer Failing when Attachments Added

Posted on 2012-12-21
18
1,148 Views
Last Modified: 2012-12-23
Have a PHPMailer routine that has been working fine sending HTML emails to users.  Just added ability to include an attachment and it now fails on send with the following error:

PHPMailer Send function failed: Could not instantiate mail function.

Using echos, I have verified that paths to the file(s) are correct, are complete (all the way back to the server's drive letter) and use the "double backslash" when assigning the path variable.  Echos verify that the file exists where indicated.

Doesn't matter if the file is a .zip (the normal) or a .pdf or .txt (also used).  Same error on both.

When I comment out just the $mail->AddAttachment() command, the email sends fine.

Here is the command (I added the "die" to see if this function was the problem):
if ($mail->AddAttachment($filepath, $name, 'base64', $mimetype) === false)
die("Failed when adding " . $filepath . '<br>');

These are individual emails to a single individual, not a blast going out to hundreds of addresses.

Can anyone point me in the right direction?

Thanks!!
Bruce
0
Comment
Question by:springthorpeSoftware
  • 8
  • 5
  • 3
  • +1
18 Comments
 
LVL 28

Expert Comment

by:chilternPC
ID: 38714715
a quciky - I assume The file has been uploaded first or is an existing file on your web server.
0
 
LVL 28

Expert Comment

by:chilternPC
ID: 38714718
if that's so can you show the code ?
0
 
LVL 82

Expert Comment

by:Dave Baldwin
ID: 38714737
Have you installed the current version of PHPMailer from http://code.google.com/a/apache-extras.org/p/phpmailer/wiki/PHPMailer ?
0
 

Author Comment

by:springthorpeSoftware
ID: 38714893
Dave: Installed about a year ago.  How do I find version info to see if I'm current?

Chiltern:  Files are already on server, not uploaded at the moment.  

Thanks, guys!!

The user has the option to either attach a .zip file (which a lot of folks can't get) or to attach the individual files from the .zip.  If the latter, routine unzips the one file into a temp folder, then adds the individual files as attachments.  I've tested with both, and with just a single .pdf.  Same error all three ways.

Done a print_r on the array holding the attachments.  Everything there seems fine.

Note that it works fine if I just comment out the $mail->AddAttachment() line.

Here's the relevant code for the email.  It is called as part of a function that is passed an order ID.  The function retrieves the data, builds the email based upon values in the data, then sends it.  Pretty basic, really.

            // Build the paths and file names.
            $zipspathF = $sitepath . "/clients/" . $cam_code . "/" . $ord_ca . "/zips";
            $temppathF = $sitepath . "/temp/" . str_pad('' . $_SESSION['sn_user_id'], 6, "0", STR_PAD_LEFT);

/*
...  Build body, email address list, etc.  Code pretty extensive, so it's been cut.
*/

// Instantiate the email class.
      $mail = new PHPMailer();

      // Prepare From: and ReplyTo addresses.
      if ($sqlType == "User") {
            $mail->IsHTML(false);
            $mail->AddReplyTo("support@thenewais.com", "AIS Support");
            $mail->SetFrom("support@thenewais.com", "AIS");
      } else {
            $mail->IsHTML(true);
            $mail->AddReplyTo($cam_primary_email, $cam_primary_name);
            $mail->SetFrom("emails@thenewais.com", $cam_alias);
      }
      
      // Prepare To: and Cc: addresses.
      $ary2 = explode(";", $to);
      
      foreach($ary2 as $value) {
            $ary = explode("|", $value);
            $mail->AddAddress($ary[0]);
            
      }
      
      if ($cc > '') {
            $ary2 = explode(";", $cc);
            foreach($ary2 as $value) {
                  $ary = explode("|", $value);
                  $mail->AddCC($ary[0]);
                  
            }
      }
      
      // Subject.
      $mail->Subject = $subj;
      
      // Importance/Priority.
      $mail->Priority = 3;
      if ($type == "Ack" || $type == "Del" || $type == "Rdy") {
            if ($ord_rush == "Y") $mail->Priority = 1;
      }
             
      // Body.      
      if ($type == "Reg")      {
            $mail->Body = $body;
      } else {

            $mail->MsgHTML($body);

            // Attachments.
            if ($type == "Del" && $del_attch != "N") {
                  
                  // Create a copy of the attachments array and fix any duplicate file names.
                  // Only affects name.  Creates "Doc(1)", "Doc(2)", etc.
                  // This prevents one attachment from overwriting a subsequent one.
                  
                  $files = $attachments;
                  foreach($files as $key => $value) {
                        $ary = array_keys($files, $value);
                        $x = count($ary);
                        if ($x > 1) {
                              $y = 1;
                              foreach($attachments as $key2 => $value2) {
                                    if ($value2 == $value) {
                                          $attachments[$key2] = $value2 . "(" . $y . ")";
                                          $y++;
                                    }
                              }
                        }
                  }
                  unset($files);

                  foreach($attachments as $filepath => $name) {
                        $ext = strtolower(substr(strrchr($filepath,'.'),1));
                        
                        if ($ext == "pdf")                                          $mimetype = "application/pdf";
                        elseif ($ext == "zip")                                    $mimetype = "application/zip";
                        elseif ($ext == "txt")                                    $mimetype = "text/plain";
                        elseif ($ext == "png")                                    $mimetype = "image/png";
                        elseif ($ext == "gif")                                    $mimetype = "image/gif";
                        elseif ($ext == "jpg" || $ext == "jpeg")      $mimetype = "image/jpeg";
                        elseif ($ext == "tif" || $ext == "tiff")      $mimetype = "image/tiff";
                        elseif ($ext == "doc" || $ext == "docx")      $mimetype = "application/vnd.ms-word.document";
                        elseif ($ext == "xls" || $ext == "xlsx")      $mimetype = "application/vnd.ms-excel";
                        else                                                             $mimetype = "application/octet-stream";
                        
                        
//                        $name = substr(strrchr($filepath, '\\'), 1);
                        echo $filepath . "; " . $name . "; " . $mimetype . '<br>';
                        if (is_file($filepath)) echo "File found!<br>";
                        else echo "Not there!<br>";
                        
//                        if ($mail->AddAttachment($filepath, $name, 'base64', $mimetype) === false) {
//                              die("Failed when adding " . $filepath . '<br>');
//                        }
                  }                  
/*                  
                  // Cleanup
                  if (is_dir($temppathF)) {
                        $files = glob($temppathF . '/*'); // get all file names
                        foreach($files as $file){ // iterate files
                          if(is_file($file))
                              unlink($file); // delete file
                        }      
                        rmdir($temppathF);
                  }
*/                  
            } // end of delivery with attachments.
            
      } // end of Reg or not.
      
      // Send the email.
      if ($mail->Send()) {
            // This is where it fails.
            ... }  
// end of relevant code
0
 
LVL 82

Expert Comment

by:Dave Baldwin
ID: 38714914
The recent versions are listed on the Downloads page: http://code.google.com/a/apache-extras.org/p/phpmailer/downloads/list  The version number is listed at the top of class.phpmailer.php .
0
 

Author Comment

by:springthorpeSoftware
ID: 38714946
Dave,
I'm using 5.2.1.  5.2.2 just came out Dec 3.  Will try new version in AM.
Bruce
0
 
LVL 82

Expert Comment

by:Dave Baldwin
ID: 38715107
I just downloaded 5.2.1 and 5.2.2 and compared the main class and they made a bunch of changes though a lot of them were just the comments.  I also found a problem in the Gmail example file.  Their version of 'preg_replace' on line 20 doesn't work.  Below is their version and the version I replaced it with.  I posted a notice on the Google code site about it.
// original version
$body             = preg_replace('/[\]/','',$body);
// my working version
$body             = preg_replace('#\\\\#','',$body);

Open in new window

http://us2.php.net/manual/en/regexp.reference.escape.php
0
 
LVL 11

Expert Comment

by:mcnute
ID: 38715356
if you use another framework such as swiftmailer. I always succeeded with swift mailer.

Swfitmailer Attachments

This wouldn't affect all of your code, just the part where you send the email.

So you would include the swiftmail class on top of your mail php page:

require_once '/path/to/swift-mailer/lib/swift_required.php';

Open in new window


Create the message like so:

//create a traonsport mail, smtp or sendmail as far as I know
$transport = Swift_SmtpTransport::newInstance('smtp.example.org', 25)
  ->setUsername('your username')
  ->setPassword('your password')
  ;

// Create the message
$message = Swift_Message::newInstance()

  // Give the message a subject
  ->setSubject('Your subject')

  // Set the From address with an associative array
  ->setFrom(array('john@doe.com' => 'John Doe'))

  // Set the To addresses with an associative array
  ->setTo(array('receiver@domain.org', 'other@domain.org' => 'A name'))

  // Give it a body
  ->setBody('Here is the message itself')

  // And optionally an alternative body
  ->addPart('<q>Here is the message itself</q>', 'text/html')

// You can alternatively use method chaining to build the attachment
$attachment = Swift_Attachment::newInstance()
  ->setFilename('my-file.pdf')
  ->setContentType('application/pdf')

$message->attach($attachment);

// Create the Mailer using your created Transport
$mailer = Swift_Mailer::newInstance($transport);

// send the message
$result = $mailer->send($message);
 

Open in new window


It always worked for me so far, I've sent dynamic pdf with it. No worries, only transport differs from server to server. Some support mail(), others do not, and I used smtp instead.
0
 

Author Comment

by:springthorpeSoftware
ID: 38715870
Dave,

Installed PHPMailer 5.2.2.  No change.  Still fails with attachment, but works fine without.  

McNute: Going to try Swift.  We'll see what happens.

Thanks, guys!
Bruce
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 

Author Comment

by:springthorpeSoftware
ID: 38716501
McNute:

Installed Swift.  Seems to take the server a little longer to process and it sends an attachment as long as it's not too large.  One or two .pdf files of less than 100K each are fine.  I haven't worked it upward gradually to see where it hits the limit.

If I attach my example .zip file (4 meg) I get the following error:

Fatal error: Maximum execution time of 30 seconds exceeded in D:\WWWRoot\TheNewAIS\software\Swift-4.2.2\lib\classes\Swift\Transport\StreamBuffer.php on line 232

Kicker on the .zip file is that it DOES get sent even though the error message shows.  The email that arrives is complete, as is the .zip attachment.

If I attach all of the docs as individual attachments (4.2 meg), I get a "FastCGI" error:

FastCGI Error
The FastCGI Handler was unable to process the request.
--------------------------------------------------------------------------------

Error Details:

•The FastCGI process exceeded configured activity timeout
•Error Number: 258 (0x80070102).
•Error Description: The wait operation timed out.
HTTP Error 500 - Server Error.
Internet Information Services (IIS)
 from the server.

On the FastCGI, no email goes out.

Note:  Using my 1and1 account for the test smtp server.  Can get dedicated smtp from site host (not 1&1), but it will take until after the new year.

These deliveries go upwards of 20 meg total, with individual documents as large as 8 meg.  Yes, I know that most public email services won't allow emails that large and have told the client, but he wants attachment options because his clients are mostly large title companies and mortgage lenders that are used to getting big documents.  

The current delivery method is a download link in the email, but more and more companies are blocking .zip downloads. (Duh! How about .zip attachments?!)  He's right on one thing, though:  The individual doc attachments will probably be the only way to deliver the info to security-conscious clients in the near future.  

So close!!  Any ideas on how to extend these time limits?  Should I close this question and post the timeout problem as a new question?

Thank you for your time and expertise!
Bruce
0
 
LVL 11

Expert Comment

by:mcnute
ID: 38716885
Open the StreamBuffer.php file which resides in D:\WWWRoot\TheNewAIS\software\Swift-4.2.2\lib\classes\Swift\Transport\ with a text-editor (NOT MS WORD) such as Notepad++.

Goto line 232 and change the value from 30 to 60 seconds. See if that resolves your timeout issue.
0
 

Author Comment

by:springthorpeSoftware
ID: 38717069
Line numbers seem a little off.  Line 232 is a "fwrite($this->_in, $bytes)".

Attaching copy of my file installed yesterday, as edited.  In that code, they set timeout at 15, (line 250) but then overwrite that with whatever is in _params['timeout'].  Spent only a few minutes browsing around, but couldn't find where values in _params array come from initially.  I forced 60 into _params['timeout'].

In any case, same error (still showing 30 seconds, not 15 or 60), same line number.  Email with attachment still gets delivered.  Still get FastCGI when using individual attachments.

Bruce
StreamBuffer.php
0
 
LVL 11

Expert Comment

by:mcnute
ID: 38717076
Swift_SmtpTransport::newInstance('domain.com', 25)
                ->setUsername('info@domain.com')
                ->setPassword('wrong_password')
                ->setTimeout(45);

Open in new window


If you set a timeout like so? What does it tell you?
0
 

Author Comment

by:springthorpeSoftware
ID: 38717182
McNute:
Same error, and still showing 30 seconds.
Bruce
0
 
LVL 11

Accepted Solution

by:
mcnute earned 500 total points
ID: 38717198
Add this to your script:

ini_set('max_execution_time', 600); 

Open in new window


This line of code was postet on stackoverflow on this question.
0
 

Author Comment

by:springthorpeSoftware
ID: 38717357
McNute:

Thanks!!  That cured the Swift error, but now both sends (zips and individual files) are giving me FastCGI error.  Thinking I'm going to have to contact the host.

You get the points!  I'll repost if host can't help.

Bruce
0
 

Author Closing Comment

by:springthorpeSoftware
ID: 38717359
Thanks to McNute for the extended time and effort!
Bruce
0
 
LVL 11

Expert Comment

by:mcnute
ID: 38717381
You're welcome! Have a nice christmas time.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Things That Drive Us Nuts Have you noticed the use of the reCaptcha feature at EE and other web sites?  It wants you to read and retype something that looks like this.Insanity!  It's not EE's fault - that's just the way reCaptcha works.  But it is …
Prologue It is often required to host multiple websites on a single instance of IIS, mostly in development environments instead of on production servers. I am sure it is not much a preferred solution on production servers but this is at least a pos…
The viewer will learn how to count occurrences of each item in an array.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

759 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now