Назад | Перейти на главную страницу

Как повторно отправить «Недоставленное письмо, возвращенное отправителю» в / var / spool / mail?

После изменения IP-адреса сервера, который был настроен как спутниковая система электронной почты, я пропустил обновление mynetworks на почтовом сервере, чтобы разрешить отправку электронных писем от имени нового IP-адреса.

Вот почему за последнюю неделю в / var / spool / mail / было написано много писем с мягким уведомлением о недоставке. Недоставленная почта возвратилась отправителю пока мы не заметили эту проблему и не исправили конфигурацию почтового сервера.

Теперь мы хотим повторно доставить отклоненные письма исходным получателям. Это означает анализ файлов в / var / spool / mail / * и извлечение исходных писем, чтобы снова отправить их с исходными заголовками. Как это сделать?

Я написал PHP-скрипт для анализа / var / spool / mail / file для повторной отправки возвращенных писем с исходными заголовками. Не забывайте изменять конфигурацию в первых строках в соответствии с вашими потребностями.

<?php
DEFINE('SIMPLIFIEDBOUNDARYCHECK', '/hostxx.mydomain.tld--');
DEFINE('TEST', true);
DEFINE('TESTRECEIVER', 'me@example.com');
$excludeReceiver = array('some@example.com');

function startsWith($haystack, $needle) {
  return $needle === "" || strpos($haystack, $needle) === 0;
}

function endsWith($haystack, $needle) {
  return $needle === "" || substr($haystack, -strlen($needle)) === $needle;
}
if(!isset($argv[1])) {
  die("resend mails: filename argument missing, e.g. /var/spool/mail/www-data");
}
$filename = $argv[1];

$handle = fopen($filename, "r");
if(!$handle)
  die("$filename could not be opened");

$state = 0;
$mail = NULL;
while(($line = fgets($handle)) !== false) {

  switch($state) {
    case 0:
      if(startsWith($line, 'Content-Description: Undelivered Message')) {
        $state = 1;
        $mail = new Mail();
      }
      break;
    case 1: // pre-header
      $trimmedLine = trim($line);
      if(empty($trimmedLine)) {
        $state = 2;
        break;
      }
      break;
    case 2: // header
      $trimmedLine = trim($line);
      if(empty($trimmedLine)) {
        $state = 3;
        break;
      }
      $mail->readHeader($line);
      // echo $line;
      break;
    case 3:
      // body
      if(endsWith(trim($line), SIMPLIFIEDBOUNDARYCHECK)) {
        $state = 0;
        $mail->send();
        break;
      }
      $mail->appendBody($line);
  }
}

fclose($handle);

class Mail {

  private $to;
  private $subject;
  private $body = '';
  private $extraHeader = '';

  public function readHeader($line) {
    if(startsWith($line, 'To: ')) {
      $this->to = substr(trim($line), 4);
    }else if(startsWith($line, 'Date: ') || startsWith($line, 'From: ') || startsWith($line, 'Content-Type: ') || startsWith($line, ' boundary="') || startsWith($line, 'MIME-Version:')) {
      $this->extraHeader .= $line;
    }else if(startsWith($line, 'Subject: ')) {
      $this->subject = substr(trim($line), 9);
    }
  }

  public function appendBody($line) {
    $this->body .= $line;
  }

  public function send() {

    global $excludeReceiver;

    if(in_array($this->to, $excludeReceiver)) {
      echo "Suppressed To: $this->to, Subject: " . $this->subject . "\n";
      return;
    }

    $receiver = TEST ? TESTRECEIVER : $this->to;
    echo "To: $receiver, Subject: " . $this->subject . "\n";
    mail($receiver, $this->subject, $this->body, $this->extraHeader);
  }
}