Avatar of springthorpeSoftware
springthorpeSoftware
Flag for United States of America asked on

PHPMailer Failing when Attachments Added

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
PHPMicrosoft IIS Web ServerJavaScript

Avatar of undefined
Last Comment
mcnute

8/22/2022 - Mon
Peter Hart

a quciky - I assume The file has been uploaded first or is an existing file on your web server.
Peter Hart

if that's so can you show the code ?
Dave Baldwin

Have you installed the current version of PHPMailer from http://code.google.com/a/apache-extras.org/p/phpmailer/wiki/PHPMailer ?
Your help has saved me hundreds of hours of internet surfing.
fblack61
springthorpeSoftware

ASKER
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
Dave Baldwin

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 .
springthorpeSoftware

ASKER
Dave,
I'm using 5.2.1.  5.2.2 just came out Dec 3.  Will try new version in AM.
Bruce
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Dave Baldwin

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
mcnute

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.
springthorpeSoftware

ASKER
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
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
springthorpeSoftware

ASKER
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
mcnute

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.
springthorpeSoftware

ASKER
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
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
mcnute

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?
springthorpeSoftware

ASKER
McNute:
Same error, and still showing 30 seconds.
Bruce
ASKER CERTIFIED SOLUTION
mcnute

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
springthorpeSoftware

ASKER
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
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
springthorpeSoftware

ASKER
Thanks to McNute for the extended time and effort!
Bruce
mcnute

You're welcome! Have a nice christmas time.