Барабашка или кривые руки: Exception Could not instantiate mail function в PHPMailer 5

Сегодня при отправке почты из скрипта на хостинге через замечательную библиотеку PHPMailer столкнулся с неожиданным исключением "Could not instantiate mail function".

Режим мейлера был выставлен в mail(). При этом обычный mail() смело работал и отправлял почту без проблем.

Я с этой проблемой справился и сейчас расскажу вам как.

Для начала приведу текст исключения:

Fatal error: Uncaught exception 'phpmailerException' with message 'Could not instantiate mail function.' in /home/bla/www/lib/phpmailer/class.phpmailer.php:687
Stack trace: #0 /home/bla/www/lib/phpmailer/class.phpmailer.php(578): PHPMailer->MailSend('Date: Thu, 19 A...', '--b1_685c964733...')
#1 /home/bla/www/controllers/mailer.php(180): PHPMailer->Send()
#2 /home/bla/www/index.php(89): include_once('/home/ukrmedto/...')
#3 {main} thrown in /home/bla/www/lib/phpmailer/class.phpmailer.php on line 687

 

Напомню, что я отправлял в режимо выставленном по умолчанию, то есть через функцию mail().

Я быстро отыскал метод MailSend() внутри PHPMailer, раскомментировал все заглушенные @mail, но в лог-файл не свалилось ни строчки. Исключение осталось на своем месте.

Я поплясял вокруг еще немножко, и прешл к здравому выводу, что к ошибке приводит последний параметр, передаваемый в mail(), а именно:

	$params = sprintf("-oi -f %s", $this->Sender);

Сначала я беззалостно убрал его прямо из кода класса. И это помогло. Письма отправились и пришли, никаких других ошибок не появилось.

Потом я подумал, что как-то это не этично — хардкодить в библиотеке, как у себя дома, и попытался расширил класс мейлера, переопределив MailSend():

include_once('lib/phpmailer/class.phpmailer.php');

class PHPMailer_Extended extends PHPMailer {
    
    /**
   * Sends mail using the PHP mail() function.
   * @param string $header The message headers
   * @param string $body The message body
   * @access protected
   * @return bool
   */
  protected function MailSend($header, $body) {
    $toArr = array();
    foreach($this->to as $t) {
      $toArr[] = $this->AddrFormat($t);
    }
    $to = implode(', ', $toArr);

    $params = sprintf("-oi -f %s", $this->Sender);
    if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) {
      $old_from = ini_get('sendmail_from');
      ini_set('sendmail_from', $this->Sender);
      if ($this->SingleTo === true && count($toArr) > 1) {
        foreach ($toArr as $key => $val) {
          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
          // implement call back function if it exists
          $isSent = ($rt == 1) ? 1 : 0;
          $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
        }
      } else {
        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
        // implement call back function if it exists
        $isSent = ($rt == 1) ? 1 : 0;
        $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
      }
    } else {
      if ($this->SingleTo === true && count($toArr) > 1) {
        foreach ($toArr as $key => $val) {
          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
          // implement call back function if it exists
          $isSent = ($rt == 1) ? 1 : 0;
          $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
        }
      } else {
        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
        // implement call back function if it exists
        $isSent = ($rt == 1) ? 1 : 0;
        $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
      }
    }
    if (isset($old_from)) {
      ini_set('sendmail_from', $old_from);
    }
    if(!$rt) {
      throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
    }
    return true;


  }
 
}

//$mail = new PHPMailer(true);
$mail = new PHPMailer_Extended(true);
...

Да, ошибка при этом пропала, но письма так и не стали отправляться. Поискав в сети, я все же остался с мыслью, что protected-методы можно переопределить в классе-наследнике. Но тогда не понятно в чем же проблема?

Признаюсь честно, я не разобрался в этом до конца. Три часа ночи все же. Плюнул, захардкодил прямо в код библиотеки и пошел спать. Главное — работает.

Все хорошо, и все работает. Надеюсь это кому нибудь поможет

Полезно(5)Бесполезно(4)

11 Responses to “ Барабашка или кривые руки: Exception Could not instantiate mail function в PHPMailer 5 ”

  1. Алексей

    Дружище!
    Ты просто спас меня!
    Пересмотрел все что можно, какие настройки сервера могут влиять на это, сравнивал с другим рабочим сервером.
    Все так же, все правильно, но phpMailer не отправлял (с той же ошибкой).
    Закомментил
    // $params = sprintf("-oi -f %s", $this->Sender);
    и все стало гут.

    Полезно(0)Бесполезно(0)
    • Городецкий

      Городецкий

      Рад помочь)

      Полезно(0)Бесполезно(0)
      • Аскар

        А вот мне комментирование не помогло
        фреймворк Yii 1.1.14
        PHPMailer - PHP email class
        Version: 5.0.0

        Замена на
        public $Mailer = 'sendmail';
        тоже не помогло

        Полезно(0)Бесполезно(0)
  2. Убрали последний параметр $params из функции mail() и все заработало. Видимо параметры sendmail заблокированы настройками безопасности хостинга.

    Спасибо за наводку!

    Полезно(0)Бесполезно(1)
    • Городецкий

      Городецкий

      Пожалуйста

      Полезно(0)Бесполезно(0)
  3. Макасим

    Все верно, работает как надо, спасибо тебе друг!

    Полезно(0)Бесполезно(0)
  4. Спасибо, ты как просто молодец! О чудо

    Полезно(0)Бесполезно(0)
  5. edmin, решение простое.
    Просто в class.phpmailer.php найди строчку
    public $Mailer = 'mail';
    И замени её на
    public $Mailer = 'sendmail';

    Полезно(3)Бесполезно(3)
  6. Аскар

    в моём случае получилось так, что я отправлял письмо в виде HTML, а там был стиль
    a:visited
    и оно как-то влияло на отправку, убрал и заработало

    Полезно(1)Бесполезно(1)
  7. Андрей

    В Joomla с какого то перепугу стало выскакивать сообщение "Mailer Error: Could not instantiate mail function"
    Погуглил, нашел данную страницу ... Спасибо за совет!!! Всё заработало.

    Менял в файле = /libraries/cegcore/vendors/phpmailer/class.phpmailer.php
    версия файла = Version: 5.2.1
    строчка № 743

    Полезно(1)Бесполезно(0)
  8. Для меня комментированиене сработало. Думал что-то не так в заголовках или параметрах, но без них тоже не отправлялось. Оказалось, что в /var/log/maillog при попытке отправки письма писалась такая ошибка: postfix/sendmail[16752]: fatal: chdir /var/spool/postfix: Permission denied. Загуглил и оказалось, что SELinux не разрешал из-под апача слать сообщения. Проверяется так: getsebool httpd_can_sendmail, возвращало httpd_can_sendmail --> off. Решается так: setsebool -P httpd_can_sendmail 1

    Полезно(0)Бесполезно(0)
Комментарии закрыты.