sendmail и ipv6
Столкнулся с проблемой, на которую потратил достаточно много времени.
Суть: при отправке письма через sendmail оно уходило с минутной задержкой. При этом sendmail в логе отчитывается "Message accepted for delivery", а удаленному серверу письмо отдает только через минуту. После ряда экспериментов выяснил зависимость этой задержки от параметра confTO_CONNECT.
Логика не подсказала причины подобного таймаута. Заметил, что процесс отправки (sendmail в отдельном процессе это делает) запускается сразу, но тупо висит. Натравливаю strace на этот процесс и наблюдаю, как он упорно пытается подключиться к удаленному серверу через ipv6 :)
Кстати, найти способ отключить поиск AAAA-записей в sendmail без пересборки не удалось. Поэтому просто отключил ipv6 на уровне ядра: добавил
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
в /etc/sysctl.conf и применил: sysctl -p.
PHP, функция mail
Функция mail в php имеет несколько моментов, про которые нужно помнить.
mail($email_to, '=?UTF-8?B?'.base64_encode($email_subj).'?=', $email_body, 'From: robot@site.com' . "\n" . 'Content-type: text/html; charset=utf-8' . "\n");
Тему письма стоит закодировать, иначе она может некорректно распознаваться почтовым клиентом:
'=?UTF-8?B?'.base64_encode($email_subj).'?='
В заголовках стоит указать заголовок From, а также тип и кодировку содержимого:
'From: robot@site.com' . "\n" . 'Content-type: text/html; charset=utf-8' . "\n"
Можно достаточно просто приложить файл к письму, не обязательно тянуть за собой какие-то библиотеки:
$f = fopen($filename, "rb"); $uniq = strtoupper(uniqid(time())); $head = "From: $from\n"; $head .= "Mime-Version: 1.0\n"; $head .= "Content-Type:multipart/mixed;"; $head .= "boundary=\"----------".$uniq."\"\n\n"; $body = "------------".$uniq."\nContent-Type:text/html; charset=utf-8\n"; $body .= "Content-Transfer-Encoding: 8bit\n\n$text\n\n"; $body .= "------------".$uniq."\n"; $body .= "Content-Type: application/octet-stream;"; $body .= "name=\"".basename($filename)."\"\n"; $body .= "Content-Transfer-Encoding:base64\n"; $body .= "Content-Disposition:attachment;"; $body .= "filename=\"".basename($filename)."\"\n\n"; $body .= chunk_split(base64_encode(fread($f, filesize($filename))))."\n";
Здесь $filename - отправляемый файл, $from - адрес отправителя, $text - текст самого письма.
Переменные $head и $body - заголовки и тело письма соответственно.
PHP, декодирование юникода
Для декодирования строки "\u0412\u0435\u0441\u0442\u0435\u0440\u043D \u041D\u0430\u0439\u0442\u0441
" можно преобразовать ее в "Вестерн Найтс
", а потом воспользоваться html_entity_decode.
Код выглядит примерно так:
$s = '\u0412\u0435\u0441\u0442\u0435\u0440\u043D \u041D\u0430\u0439\u0442\u0441'; $s = preg_replace('/\\\u0([0-9a-fA-F]{3})/','&#x\1;',$s); $s = html_entity_decode($s, ENT_NOQUOTES,'UTF-8');
iconv в PHP
Просто пара вещей, которые нужно помнить при работе с iconv. Я о них все время забываю, так что это вроде памятки.
1. //TRANSLATE//IGNORE. Именно в таком порядке и никак иначе.
2. Кодировка UTF-8 пишется через дефис. Кодировки CPNNN пишутся без дефиса: CP1251, CP866. Однако запись windows-1251 тоже допускается.