Переадресация email средствами PHP

175
27 декабря 2021, 15:40

Мой сайт получает email на адрес "user@mysite.ru", и я желаю совершить переадресацию этого сообщения на реальный почтовый адрес пользователя (скажем, "real_mail@mail.com") средствами PHP (в данном случае PHP производит дополнительную обработку сообщения, так что пересылка через настройки SMTP невозможна).

Мне удалось осуществить пересылку, но при этом в получатель видит в письме в пункте "Кому" почту "real_mail@mail.com", в то время как требуется, чтобы в качестве получателя был указан адрес, с которого произведена пересылка, т. е. "user@mysite.ru".

    $fp = fopen("php://stdin", "r");
    $parser = new MailMimeParser();
    $message = $parser->parse($fp);
    $stmt = safeq("SELECT local_email FROM users WHERE email = ?", "s", $message->getHeaderValue("From"));
    $stmt->bind_result($from);
    if(!$stmt->fetch())
        fail();
    $stmt->close();
    $to = [];
    $toheaders = array($message->getHeader("To"));
    if($message->getHeader("CC"))
        $toheaders[] = $message->getHeader("CC");
    foreach($toheaders as $toheader)
        if(isset($toheader))
            foreach($toheader->getAddresses() as $addr)
                $to[] = "SELECT email FROM users WHERE local_email = '".$db->escape_string(str_replace("@mysite.ru", "", $addr))."'";
    $resp = $db->query(join(" UNION ", $to));
    if(!$resp)
        fail();
    $to = [];
    while($result = $resp->fetch_assoc())
        $to[] = $result["email"];
    if(sizeof($to) == 0)
        fail();
    $mail = new PHPMailer(true);
    $mail->Host = 'mysite.ru';
    $mail->setFrom("$from@mysite.ru");
    $mail->Subject = $message->getHeaderValue('Subject');
    $mail->isHTML(true);
    $mail->Body = $message->getHTMLContent();
    $mail->AltBody = $message->getTextContent();
    $mail->CharSet = "UTF-8";
    foreach($message->getAllAttachmentParts() as $part)
        $mail->addStringAttachment($part->getBinaryContentStream(), $part->getFilename());
    fclose($fp);
    foreach($to as $addr) {
        $mail->addAddress($addr);
        $mail->send();
        $mail->ClearAllRecipients( );
    }
Answer 1

Это можно осуществить силами PHPMailer при условии, что вы используете SMTP как механизм отправки, то есть:

$mail = new PHPMailer(true);
$mail->isSMTP();

Идея такая: необходимо реальный адрес получателя (real_mail@mail.com) установить как BCC, а его "виртуальный" адрес (user@mysite.ru) установить как заголовок с помощью метода addCustomHeader('To', 'user@mysite.ru').

Таким образом, конверт будет адресован real_mail@mail.com, и доставка будет производиться на этот адрес. А в заголовке To будет указано user@mysite.ru, что и будет отображено конечному пользователю в его почтовом клиенте.

Правда, здесь есть один нюанс, который нужно исправить. PHPMailer устроен так, что если при подготовке письма к отправке не установлены поля To и Cc, то будет добавлен заголовок To: undisclosed-recipients:; (см. метод createHeader()).

В этом же методе далее будет добавлен и ранее установленный заголовок To: user@mysite.ru, что приведёт к наличию двух заголовков To. При этом, есть ненулевая вероятность существования анти-спам фильтра где-то на стороне клиента или его провайдера, который не пропустит e-mail, адресованный undisclosed-recipients.

Чтобы это исправить, немного допилим метод createHeader() (пилить здесь):

--- a/PHPMailer.php        2019-12-10 06:17:38.000000000 -0500
+++ b/PHPMailer.php        2019-12-21 10:55:24.000000000 -0500
@@ -2435,6 +2435,11 @@
         // Add custom headers
         foreach ($this->CustomHeader as $header) {
+            if ($header[0] === 'To') {
+                $result = str_replace('To: undisclosed-recipients:;', 'To: ' . $this->encodeHeader(trim($header[1])), $result);
+                continue;
+            }
+
             $result .= $this->headerLine(
                 trim($header[0]),
                 $this->encodeHeader(trim($header[1]))

Теперь undisclosed-recipients будет заменён на пользовательский заголовок To, если он был установлен.

Вот скрипт, использованный для тестирования (с изменёнными адресами):

<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require 'path_to/phpmailer/Exception.php';
require 'path_to/phpmailer/PHPMailer.php';
require 'path_to/phpmailer/SMTP.php';
$mail = new PHPMailer(true);
try
{
        $mail->isSMTP();
        $mail->Host = 'smtp.my.example.com';
        $mail->Port = 587;
        $mail->SMTPSecure = false;
        $mail->SMTPAutoTLS = false;
        $mail->setFrom('foo@my.example.com', 'Foo');
        $mail->addBCC('real@real.example.org');
        $mail->addCustomHeader('To', 'virtual@my.example.com');
        $mail->Subject = 'Dummy e-mail subject';
        $mail->Body = 'Dummy e-mail body';
        $mail->send();
        echo "Message has been sent\n";
}
catch (Exception $e)
{
        echo "Error while sending message: $mail->ErrorInfo\n";
}
READ ALSO
Объединение строк таблицы

Объединение строк таблицы

Помогите, пожалуйста, с SQL запросом: нужно объединить поля message для записей, у которых совпадают поля ref в такой примерно таблице:

82
Отображение нужного блока по нажатию на кнопку

Отображение нужного блока по нажатию на кнопку

Имеются кнопки и идущие за ними блокиУ кнопок одинаковый класс и у блоков также

175
Как сделать лучше фронт часть?

Как сделать лучше фронт часть?

Ситуация такова Есть 22 пунктов слева Есть слайдер справа( слайдер из фотографии ) При клике на пункт, слайдер должен иметь те фото что относятся...

207