Cherka Trova
Доброго времени суток. Вот такая проблемка возникла. Может, кому-то приходилось сталкиваться. Ответ нужен быстрый..
Скрипт на php достает из ящика письмо, выделяет из него тело в формате, приведенном ниже (письмо сформировано в Ms Outlook в формате html со вставленными картинками и прикрепленным документом).
Задача: сформировать письмо, идентичное по отображению этому и сохранить его тело в файл для дальнейшей рассылки другим скриптом.
Заранее спасибо за ответы.

формат письма

@темы: Алгоритмы, mail(), PHP, Вопросы

Комментарии
29.01.2008 в 15:20

Для того, чтобы забрать письмо "курим" мануал на тему fsockopen и RFC соответсвующего протокола (POP/IMAP).
Сохраняешь полученное в файл, разделив headers и body любым удобным тебе разделителем.
Для отсылки просто читаешь файл и функции mail() отдаёшь headers и body вычитанные из файла.
Никаких преобразований не понадобятся.
29.01.2008 в 15:23

Cherka Trova
С забором письма проблем нет (иначе как бы я показал вам эту структуру), но вот в таком виде с замененными в header адресами отправителя и получателя, оно не отправляется нормально..
29.01.2008 в 15:27

Можно сохранённый файл выложить куда-то?
29.01.2008 в 15:39

Cherka Trova
В смысле файл с телом письма и файл с заголовками? (я предпочел разделить их)
29.01.2008 в 15:46

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Garoth
оно не отправляется нормально
А как именно отправляется?
29.01.2008 в 15:57

Cherka Trova
Приходит в точности тот текст, который я показал. И отображается именно так в теле письма.
29.01.2008 в 16:07

Cherka Trova
Kuroi Kitsune
www.liogrand.com/mail/headers.dat - Заголовки (если нужно вытянуть что-то еще, скажите..)
www.liogrand.com/mail/body.txt - Тело (сравните с тем, что я вам дал, один в один)
29.01.2008 в 16:17

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Garoth

Проблема в заголовках. Самый главный для такого вида письма заголовок Content-Type: multipart/alternative;
boundary="----=_NextPart_002_0004_01C85E16.5BF9FB20" вы отправляете в теле, а не в заголовках.
29.01.2008 в 16:20

Cherka Trova
хм... но ведь он и приходит в теле. т.е. мне надо выделить его оттуда? Хорошо, но почему не первую часть
------=_NextPart_000_0002_01C85E16.5BF9FB20
Ведь она обрамляет все письмо..
29.01.2008 в 16:23

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Общий принцип постороения такого сообщения следующий:

В заголовках необходимо передать значение "Content-Type: multipart/alternative; boundary=РАЗДЕЛИТЕЛЬ1"

Этот заголовок говорит о том, что содержание писмо состоит из нескольких альтернативных кусков, которые отображаются в зависимости от настироек клиента. Например, можно в одином пистме оиправить несколько кусков в разных кодировках. Каждый кусок такого писма является самостоятельным полноценным телом, то есть содержит собственный набор заголовков. В самом теле разделитель начинается с "--". Кроме того, для обознаячение окончания действия разделителя используюется закрывающий разделитель, не только начинается, но и заканчивается на "--" Пример всего этого:

//Основные завголоки я пропускаю

Content-Type: multipart/alternative; boundary="=1261023517="

--=1261023517=
MIME-Version: 1.0
Content-Type: text/plain; charset="cp1251"
Content-Transfer-Encoding: base64

0+Lg5uDl7PvpIOjn5ODy5ev8IEFkU2Vuc2UsDQrM+yDv7vH76+Dl7CDC4Owg/fLuIO/o8fzs7iwg
9/Lu4fsg8e7u4fno8vwg7

--=1261023517=
MIME-Version: 1.0
Content-Type: text/html; charset="cp1251"
Content-Transfer-Encoding: base64

PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBYSFRNTCAxLjAgVHJhbnNpdGlvbmFs
Ly9FTiIgImh0dHA6Ly93d3cudzMub3JnL1RSL3hodG1sMS9EVEQveGh0bWwxLXRyYW5zaXRpb25h
bC5kdGQiPg0KPGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiIGxhbmc9
ImVuIiBkaXI9Imx0ciI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg
Y29udGVudD0iIGNoYXJzZXQ9d2luZG93cy0xMjUxIiAvPg0KPHRpdGxlPkFkU2Vuc2UgTmV3c2xl
dHRlcjwvdGl0bGU+DQoNCjwvaGVhZD4NCg0KPGJvZHk

--=1261023517=--

Далее. Для того чтобы картинки выводились не после письма как вложения, а в самом тексте, необходимо указывать заголовок Content-Type: multipart/related; boundary=РАЗДЕЛИТЕЛЬ2;type="text/html". Здесь, РАЗДЕЛИТЕЛЬ2 - это уже дроугой разделитель, который используется в этом альтернативном блоке письма. Правила его использования точно такие же. Дальше, вставляем там где надо саму картинку: <img height="100" width="204" src="cid:ИДЕНТИФИКАТОР"> Послпо окончании контента, выводим наш внутренний разделитель "РАЗДЕЛИТЕЛЬ2" и после этого набор завголовков такого типа:

Content-Disposition: inline; filename=image.gif
Content-Transfer-Encoding: base64
Content-Type: image/gif;name="image.gif"
Content-Id: <ИДЕНТИФИКАТОР>

А после этого, собственно сам контент картинки. Не забываем потом закрыть внетренний разделитель, а потом и внешний. Да, и не забваем, что весь контент у меня указывается как кодированный base64, а следовательно в тело письма его надо вставлять именно кодированным, в том числе и контент картинки.
29.01.2008 в 16:28

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
В данном случае, MS Outlook весь контент вставил в еще один уровень разделения. В принципе, это не лишнее, но и не обязательное действие.
Хорошо, но почему не первую часть
Тут вы правы, я не доглядел - вынести в заголовки обязательно первый, высший уровень разделения. Когда программа определяет такой заголовок, она получает инструкцию на разбиение письма и поиск дополнительных заголовков в теле. В противном слуае, она выводит все "as is".
29.01.2008 в 16:32

Cherka Trova
Т.е. вы предлагаете мне из письма такого вида выделать отдельно части и их переносить в новую форму... хм.. это вариант, конечно, но, мне кажется, есть метод проще..
В любом случае спасибо за разъяснения..
Вопрос на маленькое уточнение: если я передам в mail() в headers строку "MIME=Version 1.0" Дублировать ее уже не надо будет, так?
И еще: обязательно ли в письме должна присутствовать строка, которую мы видим стоящей первой?
"Это составное сообщение в формате MIME."
29.01.2008 в 16:59

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Переделывать ничего не нужно. На самом деле, нужно просто внимательно проанализировать структуру письма, чтобы отправить нужные заголовки.

PS: Сейчас как раз этим и занимаюсь. Насчет переноса заголовка я немного поторопился - судя по всему тело в порядке, а вы где-то теряете еще один заголовок, который описывает самы верхнгий уровень разделения. ИМХО, как все форматы от мелкомягкого, тут все переусложнено.
29.01.2008 в 17:00

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
обязательно ли в письме должна присутствовать строка - не думаю. Лучше старавться избегать лишних строк.
Вопрос на маленькое уточнение: если я передам в mail() в headers строку "MIME=Version 1.0" Дублировать ее уже не надо будет, так? Нет, не надо. Точнее говоря, в каждом отдельном куске тела, можно и повторять.
29.01.2008 в 17:05

Этот код у меня отослал приведённый пример и Apple Mail отобразило всё с картиками и HTML форматированием:

<?

/* Header должны содержать MIME-Version, Content-Type */
$header "Date: Wed, 23 Jan 2008 23:19:08 +0300\n";
$header .= "To: [email protected]\n";
$header .= "From: =?koi8-r?B?6czY0SDsxdfJzg==?= <[email protected]>\n";
$header .= "Reply: =?koi8-r?B?6czY0SDsxdfJzg==?= <[email protected]>\n";
$header .= "Sender: =?koi8-r?B?6czY0SDsxdfJzg==?= <[email protected]>\n";
$header .= "Subject: Test\n";
$header .= "MIME-Version: 1.0\n"
$header .= "Content-Type: multipart/mixed; boundary=\"----=_NextPart_001_0003_01C85E16.5BF9FB20\"\n\n"// boundary получаем из body простым regexp, надеюсь это не надо расписывать?

/* Читаем из файла body */
$body file_get_contents("body");

/* посылаем и проверяем - ушло ли? */
$ret mail("[email protected]""test"$body$header);
var_dump($ret);

?>



29.01.2008 в 17:09

Cherka Trova
Kuroi Kitsune FVA сенкс)) как только доберусь до кодика - проверю))
29.01.2008 в 17:13

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Kuroi Kitsune А вложение скорее всего не отобразилось?
29.01.2008 в 17:23

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Garoth Все, разобрался. Тело не трогаем, а в заголовки добавляем следующий -
Content-Type: multipart/mixed;boundary="----=_NextPart_000_0002_01C85E16.5BF9FB20"

То есть в принципе тоже самое что предлагал Kuroi Kitsune, только с самым верхним разделителем.
29.01.2008 в 17:25

Cherka Trova
Огромное спасибо, ребят.
31.01.2008 в 22:25

Cherka Trova
FVA слушай, вот с картинками вставными вопрос. обязательно чтобы всавить картинку писать именно multipart/related или можно к заголовку куска с картинкой добавить Content-Disposition: inline; filename="image.gif"
в заголовке письма стоит multipart/alternative . Как думаешь, может это сработать?

01.02.2008 в 10:21

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Garoth Нет, Блок с html и картинками обязательно определять как multipart/related - дословно это означает многосложный/связаный. А multipart/alternative - это многосложный/альтернативный, то есть взаимозаменяющий. =) То есть нужно соблюдать примерно такую структуру:

multipart/alternative
--Разделитель1
text/plain
--Разделитель1
multipart/related
--Разделитель2
text/html
--Разделитель2
image/jpg
--Разделитель2
image/png
--Закрываем Разделитель2--
Закрываем Разделитель1--
01.02.2008 в 10:23

Cherka Trova
Ясно... тело придется переписывать на порядок серьезнее, чем предполагалось изначально. чтож, спасибо за помощь.
01.02.2008 в 10:33

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Garoth А зечем переписываете?
01.02.2008 в 10:41

Cherka Trova
Просто в данном варианте тело письма представляет собой следующее:

--Разделитель_0
Content-Type: multipart/alternative;
boundary="Разделитель_1"

--Разделитель_1
Content-Type: text/plain;
charset="koi8-r"
Content-Transfer-Encoding: quoted-printable

(текст простой)

-- Разделитель_1
Content-Type: text/html;
charset="koi8-r"
Content-Transfer-Encoding: quoted-printable

(текст с html)

--Разделитель_1--

--Разделитель_0
Content-Type: image/jpeg;
name="mailhead.jpg"
Content-Transfer-Encoding: base64
Content-ID: .....

(тело картинки раз)

--Разделитель_0
Content-Type: image/jpeg;
name="www.jpg"
Content-Transfer-Encoding: base64
Content-ID: ......

(тело картинки 2)

--Разделитель_0--

Как видите, она сильно отличается от того, что требуется. И придется как-то куски извлекать целиком вместе с заголовками и их по новой расставлять в разделителях.
01.02.2008 в 10:54

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Garoth Такой вариант построения тоже работает. =) Просто ИМХО, он переусложнен. =)
01.02.2008 в 10:57

Cherka Trova
Дык в том-то и дело, что не работает.
Картинки отображаются аттачами и одновременно вклеиваются в текст (а в мозиловской птыце не вклеиваются вовсе). Шефа это категорически не устраивает.
01.02.2008 в 11:35

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
<?
$headers 
="Date: Wed, 23 Jan 2008 23:19:08 +0300
To: [email protected]
From: =?koi8-r?B?6czY0SDsxdfJzg==?= <[email protected]>
Reply: =?koi8-r?B?6czY0SDsxdfJzg==?= <[email protected]>
Sender: =?koi8-r?B?6czY0SDsxdfJzg==?= <[email protected]>
Subject: =?koi8-r?B?7s/Xz9PUySBMSU8gR1JBTkQ=?=
Content-Type: multipart/mixed;
    boundary=\"----=_NextPart_000_0002_01C85E16.5BF9FB20\""
;

$content "Это составное сообщение в формате MIME.

------=_NextPart_000_0002_01C85E16.5BF9FB20
Content-Type: multipart/related;
    boundary=\"----=_NextPart_001_0003_01C85E16.5BF9FB20\"


------=_NextPart_001_0003_01C85E16.5BF9FB20
Content-Type: multipart/alternative;
    boundary=\"----=_NextPart_002_0004_01C85E16.5BF9FB20\"


------=_NextPart_002_0004_01C85E16.5BF9FB20
Content-Type: text/plain;
    charset=\"koi8-r\"
Content-Transfer-Encoding: base64

тут простой текст

------=_NextPart_002_0004_01C85E16.5BF9FB20
Content-Type: text/html;
    charset=\"koi8-r\"
Content-Transfer-Encoding: quoted-printable

тут контент html

------=_NextPart_002_0004_01C85E16.5BF9FB20--

------=_NextPart_001_0003_01C85E16.5BF9FB20
Content-Type: image/jpeg;
    name=\"image001.jpg\"
Content-Transfer-Encoding: base64
Content-ID: <[email protected]>

Тут контент картинки

------=_NextPart_001_0003_01C85E16.5BF9FB20--

------=_NextPart_000_0002_01C85E16.5BF9FB20
Content-Type: application/msword;
    name=\"=?koi8-r?B?58nE0sHXzMnLwSAxLmRvYw==?=\"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
    filename=\"=?koi8-r?B?58nE0sHXzMnLwSAxLmRvYw==?=\"


Тут контент файла

------=_NextPart_000_0002_01C85E16.5BF9FB20--"
;

mail(""""$content$headers);

?>




Все приходит. =)
01.02.2008 в 11:41

Cherka Trova
Вот и еще один вариант. Но ведь это не совсем то, что приходит в итоге.. все равно приходится дописывать заголовки.
01.02.2008 в 11:49

Будем же учиться хорошо мыслить - вот основной принцип морали (с) Паскаль
Garoth Это не еще один вариант. Это полностью то тело, которое вы показвали. При этом добавлен всего один заголовок к переменной header:

Content-Type: multipart/mixed;
boundary=\"----=_NextPart_000_0002_01C85E16.5BF9FB20\"
01.02.2008 в 11:53

Cherka Trova
Хм.. в упор не вижу в моем письме заголовка
Content-Type: multipart/related;
boundary=\"----=_NextPart_001_0003_01C85E16.5BF9FB20\"

видимо, я опять сильно туплю...

Расширенная форма

Редактировать

Подписаться на новые комментарии
Получать уведомления о новых комментариях на E-mail