0

Friends, please explain to me why PHPMailer does not send an email?

He must send a letter after payment. The usual mail() function works, but with PHPMailer I already broke my head. HELP

After payment, this file receives a notification from Yandex that the payment has been made. I made a condition that if the payment is made, then a corresponding letter is sent to the mail.

works, despite the mistake

Fatal error: Uncaught TypeError: Argument 1 passed to YandexCheckout\Model\Notification\NotificationWaitingForCapture::__construct() must be of the type array, null given, called in /home/birdyxru/public_html/test/requests.php on line 25 and defined in /home/birdyxru/public_html/test/assets/lib/Model/Notification/NotificationWaitingForCapture.php:72 Stack trace: #0 /home/birdyxru/public_html/test/requests.php(25): YandexCheckout\Model\Notification\NotificationWaitingForCapture->__construct(NULL) #1 {main} thrown in /home/birdyxru/public_html/test/assets/lib/Model/Notification/NotificationWaitingForCapture.php on line 72

<?php
ini_set('display_errors', '1');
ini_set('display_startup_errors', '1');
error_reporting(E_ALL);
require 'assets/lib/autoload.php';
require 'db/connect.php';

// Получите данные из POST-запроса от Яндекс.Кассы
$source = file_get_contents('php://input');
$requestBody = json_decode($source, true);

// Создайте объект класса уведомлений в зависимости от события
// NotificationSucceeded, NotificationWaitingForCapture,
// NotificationCanceled,  NotificationRefundSucceeded
use YandexCheckout\Model\Notification\NotificationSucceeded;
use YandexCheckout\Model\Notification\NotificationWaitingForCapture;
use YandexCheckout\Model\NotificationEventType;
use YandexCheckout\Model\PaymentStatus;

try {
    $notification = ($requestBody['event'] === NotificationEventType::PAYMENT_SUCCEEDED)
    ? new NotificationSucceeded($requestBody)
    : new NotificationWaitingForCapture($requestBody);
} catch (Exception $e) {
    // Обработка ошибок при неверных данных
}

// Получите объект платежа
$payment = $notification->getObject();
if($payment->getStatus() === PaymentStatus::SUCCEEDED) {
    $payment_id = $payment->getId();
}


if(isset($payment_id)) {
    $email = R::getCell("SELECT `email` FROM `logs` WHERE `payment_id` = '$payment_id'");
    $date = R::getCell("SELECT `date` FROM `logs` WHERE `payment_id` = '$payment_id'");
    $time = R::getCell("SELECT `time` FROM `logs` WHERE `payment_id` = '$payment_id'");
    $report_name = strtok("$email", '@') . ' ' . $date . ' ' . $time;
    // Отправка сообщения
    $mailTo = $email; // Ваш e-mail
    $subject = "На сайте совершен платеж"; // Тема сообщения
    // Сообщение
    $message = "Платеж на сумму: " . $report_name . "<br/>";
    $message .= "Детали платежа: " . $payment->description . "<br/>";
    
    $headers= "MIME-Version: 1.0\r\n";
    $headers .= "Content-type: text/html; charset=utf-8\r\n";
    $headers .= "From: info@site.ru <info@site.ru>\r\n";
    
    mail($mailTo, $subject, $message, $headers);
}
?>

does not work :(

<?php
require 'assets/lib/autoload.php';
require 'db/connect.php';
require 'mailer/src/PHPMailer.php';

// Получите данные из POST-запроса от Яндекс.Кассы
$source = file_get_contents('php://input');
$requestBody = json_decode($source, true);
// Создайте объект класса уведомлений в зависимости от события
// NotificationSucceeded, NotificationWaitingForCapture,
// NotificationCanceled,  NotificationRefundSucceeded
use YandexCheckout\Model\Notification\NotificationSucceeded;
use YandexCheckout\Model\Notification\NotificationWaitingForCapture;
use YandexCheckout\Model\NotificationEventType;
use YandexCheckout\Model\PaymentStatus;
try {
  $notification = ($requestBody['event'] === NotificationEventType::PAYMENT_SUCCEEDED)
    ? new NotificationSucceeded($requestBody)
    : new NotificationWaitingForCapture($requestBody);
} catch (Exception $e) {
    // Обработка ошибок при неверных данных
}
// Получите объект платежа
$payment = $notification->getObject();
if($payment->getStatus() === PaymentStatus::SUCCEEDED) {
    $payment_id = $payment->getId();
}

use PHPMailer\PHPMailer\PHPMailer;

if(isset($payment_id)) {
    $email = R::getCell("SELECT `email` FROM `logs` WHERE `payment_id` = '$payment_id'");
    $date = R::getCell("SELECT `date` FROM `logs` WHERE `payment_id` = '$payment_id'");
    $time = R::getCell("SELECT `time` FROM `logs` WHERE `payment_id` = '$payment_id'");
    $report_name = strtok("$email", '@') . ' ' . $date . ' ' . $time;
   
    $mail = new PHPMailer();
    //Set who the message is to be sent from
    $mail->setFrom($email_admin, $from_name);
    //Set an alternative reply-to address
    $mail->addReplyTo($email_admin, $from_name);
    //Set who the message is to be sent to
    $mail->addAddress($email);
    //Set the subject line
    $mail->Subject = 'PHPMailer mail() test';
    //Read an HTML message body from an external file, convert referenced images to embedded,
    //convert HTML into a basic plain-text alternative body
    $message = 'Привет ' . $report_name;
    $mail->msgHTML($message);    
    //Replace the plain text body with one created manually
    $mail->AltBody = 'This is a plain-text message body';
    //Attach an image file
    $mail->addAttachment('images/phpmailer_mini.png');

    //send the message, check for errors
    if (!$mail->send()) {
        echo 'Mailer Error: ' . $mail->ErrorInfo;
    } else {
        echo 'Message sent!';
    }
}
?>

I guess the problem is in logic or syntax

Martin
  • 19,815
  • 6
  • 53
  • 104
  • 1
    Are you getting any errors? If not - how are you so sure your messages aren't being sent correctly by PHPMailer as opposed to just being trapped by a spam filter (or some other intermediary)? The latter seems likely, considering you haven't explicitly set any SMTP connection information here, and messages will by default be sent through PHP's built-in `mail()` function ([source](https://stackoverflow.com/questions/35921989/phpmailer-default-smtp-settings)). This usually [leads to delivery problems](https://stackoverflow.com/questions/18229279/sending-email-via-php-mail-function-goes-to-spam). – esqew Nov 18 '20 at 19:13
  • the letter via mail () is sent correctly and falls into the "Important" category. I can't look at the errors, because the file just accepts POST and does something by itself. – Ruslan Abdulloev Nov 18 '20 at 19:32
  • 1
    Why exactly does accepting a POST request preclude you from debugging your script...? Can you elaborate on that? – esqew Nov 18 '20 at 19:36
  • to be honest, I just don't know how to look at errors if they are not shown in the browser. – Ruslan Abdulloev Nov 18 '20 at 19:37
  • 2
    Debugging is a core skill for any language - if you're not familiar with how to debug your scripts, you should really revisit some of the more [fundamental documentation on the topic](https://www.php.net/manual/en/debugger.php). For PHP specifically there are also plenty of extremely helpful resources here on Stack Overflow: [How do I get PHP errors to display?](https://stackoverflow.com/questions/1053424/how-do-i-get-php-errors-to-display), [How do you debug PHP scripts?](https://stackoverflow.com/questions/888/how-do-you-debug-php-scripts) – esqew Nov 18 '20 at 19:48
  • Once you've been able to successfully leverage some of the information in the above linked articles, you should be able to come back and edit the body of your question to include information about the errors you're encountering (or a lack thereof). – esqew Nov 18 '20 at 19:49
  • Maybe you should require "SMTP.php" too. Require that and "PHPMailer.php" after "use PHPMailer\PHPMailer\PHPMailer". Also, be sure your file is UTF-8 encoded. – AbsoluteBeginner Nov 18 '20 at 23:14
  • Argument 1 passed to YandexCheckout\Model\Notification\NotificationWaitingForCapture::__construct() must be of the type array, null given, called in /home/birdyxru/public_html/test/requests.php on line 22 and defined in /home/birdyxru/public_html/test/assets/lib/Model/Notification/NotificationWaitingForCapture.php:72 Stack trace: #0 /home/birdyxru/public_html/test/requests.php(22): YandexCheckout\Model\Notification\NotificationWaitingForCapture->__construct(NULL) #1 {main} thrown in /home/birdyxru/public_html/test/assets/lib/Model/Notification/NotificationWaitingForCapture.php on line 72 – Ruslan Abdulloev Nov 19 '20 at 12:18
  • I managed to see the following coat – Ruslan Abdulloev Nov 19 '20 at 12:18

2 Answers2

0

Note that by using PHPMailer without calling isSMTP(), you are also using mail() behind the scenes.

Without more debug info, I'm going to take a flying guess at what's wrong:

You have not set your character set.

You've got Cyrillic characters in your content, but you have not changed the character set away from the default ISO-8859-1. This is very likely to result in errors.

Assuming you're using UTF-8, you need to tell PHPMailer that like this:

$mail->CharSet = 'utf-8';

It may be working with mail() when used directly because your PHP installation may be set to use UTF-8, however, PHPMailer doesn't use that as a default as it's not always available on all platforms (e.g. if the mbstring extension is disabled).

Synchro
  • 29,823
  • 14
  • 69
  • 85
0

Let's explore what your error message says:

Fatal error: Uncaught TypeError: Argument 1 passed to YandexCheckout\Model\Notification\NotificationWaitingForCapture::__construct() must be of the type array, null given,

Argument 1 must be an array, but is given as null.

What is "argument 1"?

new NotificationWaitingForCapture($requestBody);

When a new object is instantiated it runs the __construct method, which the error references, so it is the line mentioned above, so this in turn means that $requestBody is the "Argument 1" and for whatever reason, holds a null value.

The PHP Manual states:

NULL is returned if the json cannot be decoded or if the encoded data is deeper than the recursion limit.

This is the cause of your issue.

Suggested Fix:

You need to check your POST data is populated, rather than simply assume it is, so update your JSON_DECODE to this:

// Получите данные из POST-запроса от Яндекс.Кассы
$source = file_get_contents('php://input');
$requestBody = json_decode($source, true);
if(empty($requestBody)){
   echo "POSTED data is empty! / Опубликованные данные пусты!";
   exit;
}
Martin
  • 19,815
  • 6
  • 53
  • 104
  • The error really disappeared, but the email was never sent. There is an error, because the array is transferred at a certain moment after payment. – Ruslan Abdulloev Nov 19 '20 at 13:17
  • @РусланАбдуллоев The error you have shown in your question is caused by the array being *null*. If the email was never sent but the rest of the code worked ok then you need to explore why, We can't do this for you. – Martin Nov 19 '20 at 14:00
  • I am completely confused. I have no errors at the moment, but still nothing works. I do not know what to do. – Ruslan Abdulloev Nov 19 '20 at 16:44
  • @РусланАбдуллоев your first code block in your question uses PHP `mail` function, your second code block uses PHPMailer. You should use PHPMailer. You should also use PHPMailer Exceptions to catch exceptions. Also use `$mail->SMTPDebug = 2` to output debug messages to check everything is working correctly, or not. – Martin Nov 19 '20 at 17:59
  • ```2020-11-20 07:18:17 3 Connection: opening to mail.birdyx.ru:465, timeout=300, options=array() 2020-11-20 07:18:17 3 Connection: opened 2020-11-20 07:18:46 1 CLIENT -> SERVER: QUIT 2020-11-20 07:19:16 1 CLIENT -> SERVER: QUIT 2020-11-20 07:20:18 1 CLIENT -> SERVER: QUIT 2020-11-20 07:22:02 1 CLIENT -> SERVER: QUIT 2020-11-20 07:22:48 1 CLIENT -> SERVER: QUIT 2020-11-20 07:23:19 1 CLIENT -> SERVER: QUIT``` – Ruslan Abdulloev Nov 20 '20 at 07:24
  • @РусланАбдуллоев `$mail->send();` should be wrapped in a `try{ ... }` block, not an `if` statement. – Martin Nov 20 '20 at 10:26