Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
Здравстсвуйте!
Может быть кто-то сталкивался с проблеммой как у меня:
Взял программу для отправки почты из книги Тома Кайта "Oracle для профессионалов", реализована с помощью utl_smtp.
И работает она как нужно с единственным недостатком..
На Яндексе письма отображаются корректно - по русски везде где надо.
В Lotus Notes тоже как надо.
В Outlook-е, mail.ru, hotmail.com - тоже нормально когда захожу в само письмо, а до этого, в списке писем, тема письма нечитаемая.
В hotmail, когда меняю кодировку - прочитать совсем немогу ни на какой.
В mail.ru могу читать, когда задаю Кирилицу KOI8-R.
В общем на разных серверах русские буквы в теме письма (в списке писем) отображаются разными кодировками, а зайдёшь в письмо - там всё нормально.
Если кто-нибудь что-нибудь подскажет, буду очень благодарен.
11 июл 08, 11:10    [5920361]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
честно говоря вообще сомневаюсь что на PL/SQL можно написать программу отправки почты чтобы небыло проблемм с кодировками.. раз уж Том Кайт несмог написать, незнаю у кого лучше получится.
11 июл 08, 11:13    [5920392]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировк  [new]
Batsall
Member

Откуда: Москва
Сообщений: 360
Делаю так, вроде везде отображается
   
PROCEDURE   SEND_MAIL (
...
   s#subject     IN   VARCHAR2,
...
) IS
FUNCTION mimeheader_encode (s#string VARCHAR2)
      RETURN VARCHAR2
   IS
   BEGIN
      RETURN    '=?windows-1251?B?'
             || UTL_RAW.cast_to_varchar2
                   (UTL_ENCODE.base64_encode
                                 (UTL_RAW.cast_to_raw (CONVERT (s#string,
                                                                'CL8MSWIN1251'
                                                               )
                                                      )
                                 )
                   )
             || '?=';
   END;
...
BEGIN
...
UTL_SMTP.write_raw_data
                          (c,
                           UTL_RAW.cast_to_raw (   'Subject: '
                                                || mimeheader_encode
                                                                    (s#subject)
                                                || UTL_TCP.crlf
                                               )
                          );
...
END;
11 июл 08, 11:19    [5920475]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
Nuri
Member

Откуда: Архангельск
Сообщений: 625
Сдается мне, что в этой программе в заголовок письма явно не пишется, в какой оно кодировке, отсюда все проблемы. Добавьте в заголовок Content-Type: text/plain; charset=
Щас посмотрел письма обычные, там в теме перед текстом явно написана такая фигня: "Subject: =?koi8-r?бла-бла-бла"
11 июл 08, 11:19    [5920480]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
Nuri,
если не трудно прокомментируйте пожалуйста как это сделать:

Mail_Pkg.send (p_sender_email => 'SPeshkov@irk.sibirtelecom.ru', --используется пакет Тома Кайта для отправки письма.
p_from => 'SPeshkov@irk.sibirtelecom.ru',
p_to => Mail_Pkg.ARRAY(C_EMAIL),
p_subject => convert('присядте, пожалуйста - ваш счёт (test)','CL8KOI8R','CL8MSWIN1251'),
p_body => v);

В месте, выделенном зелёным, указывается тема письма.
11 июл 08, 11:46    [5920730]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PaulEr
Member

Откуда:
Сообщений: 3794
У меня вот такая процедура работает, в аутлуке русские буквы показывет, правда отправку на разные сервера нет возможности проверить:

CREATE OR REPLACE PROCEDURE MY.P_SEND_MAIL_MV (
sender_name in varchar2,
sender_email in varchar2,
receiver_name in varchar2,
receiver_email in varchar2,
subject in varchar2,
text in varchar2,
attachment_name in varchar2,
attachment_type in varchar2
) 
is
l_amt number:=2048;
l_off number:=1;
l_raw raw(4096);
bodies   long;
conn utl_smtp.connection;
boundary varchar2(256) := '-----7D81B75CCC90D2974F7A1CBD';
first_boundary varchar2(256) := '--'||boundary;
last_boundary varchar2(256) := '--'||boundary||'--';
multipart_mimetype varchar2(256) := 'multipart/mixed; boundary="'||boundary||'"';

begin
conn :=utl_smtp.open_connection('ip',25);
utl_smtp.ehlo(conn,'ip');
utl_smtp.mail(conn, sender_email);
utl_smtp.rcpt(conn, receiver_email);
utl_smtp.open_data(conn);
utl_smtp.write_raw_data(conn, utl_raw.cast_to_raw('From: '||sender_name));
utl_smtp.write_data(conn, utl_tcp.crlf);
utl_smtp.write_raw_data(conn, utl_raw.cast_to_raw('To: '||receiver_email));
utl_smtp.write_data(conn, utl_tcp.crlf);
utl_smtp.write_raw_data(conn, utl_raw.cast_to_raw('Subject: '||subject));
utl_smtp.write_data(conn, utl_tcp.crlf);
utl_smtp.write_data(conn, 'MIME-version: 1.0'||utl_tcp.CRLF);
utl_smtp.write_data(conn, 'Content-Type: '||multipart_mimetype||utl_tcp.CRLF);
utl_smtp.write_data(conn, utl_tcp.crlf);
utl_smtp.write_data(conn, 'This is a multi-part message in MIME format.' ||utl_tcp.CRLF);
utl_smtp.write_data(conn, first_boundary||utl_tcp.CRLF);
utl_smtp.write_data(conn, 'Content-Type: text/plain; charset="Windows-1251"'||utl_tcp.CRLF);
utl_smtp.write_data(conn, 'Content-Transfer-Encoding: quoted-printable'||utl_tcp.CRLF);
utl_smtp.write_data(conn, utl_tcp.crlf);
utl_smtp.write_raw_data(conn, utl_raw.cast_to_raw(text));
utl_smtp.write_data(conn, utl_tcp.crlf);
utl_smtp.write_data(conn, first_boundary||utl_tcp.CRLF);
utl_smtp.write_data(conn, 'Content-Type: '||attachment_type||utl_tcp.CRLF);
utl_smtp.write_data(conn, 'Content-Transfer-Encoding:(base64)'||utl_tcp.CRLF);
utl_smtp.write_data(conn, 'Content-Disposition: attachment; filename='||attachment_name);
utl_smtp.write_data(conn, utl_tcp.crlf);
utl_smtp.write_data(conn, utl_tcp.crlf);
for i in 
 ( select RN, DATE_RUN, TEXT_RUN from bio_snapshot_run where date_run between sysdate-1 and sysdate order by date_run,rn desc)
loop 
bodies:='Номер: '||i.RN||' Дата: '||to_char(i.DATE_RUN,'dd.mm.yyyy hh24:mi:ss')||' Результат: '||i.TEXT_RUN;  
    utl_smtp.write_raw_data(conn, utl_raw.cast_to_raw(chr(13)||chr(10)||Bodies));    
end loop;      
utl_smtp.write_data(conn, utl_tcp.crlf);
utl_smtp.write_data(conn, last_boundary);
utl_smtp.close_data(conn);
utl_smtp.quit(conn);
exception when others then p_exception(0,'Ошибка, суши вёсла!');
end;
/
11 июл 08, 12:01    [5920876]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
Elic
Member

Откуда:
Сообщений: 29990
PSergeyA
присядте, пожалуйста
11 июл 08, 12:25    [5921062]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
Большое спасибо всем за помощь!, нужно время чтобы использовать ваши советы, а потом, напишу чем дело закончилось..
11 июл 08, 12:27    [5921088]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
Ещё раз благодарю всех за попытку помочь!
К сожалению мне ни один совет не помог.
Проблемма в том что на некоторых почтовых серверах тема письма нормально по русски, но на большенстве выводится не читаемо (в списке писем). Если зайти в само письмо, там тоже иногда в письме тема по русски, иногда и в письме она не ичтаемая.
Похоже что готового решения не найти, нужно разбираться самому что означают все настройки и как использовать, что для чего, хотя времени на это нет совсем, но похоже всё равно по другому не получится.
15 июл 08, 09:11    [5933698]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
hardsign
Member

Откуда: Оттуда... Как оттуда???
Сообщений: 137
1. Изучить RFC (не помню номер) на почтовые собщения.
2. Из п.1 становится понятно, что SMTP-сервер не обязан обрабатывать 8-битные символы в заголовке письма, в т.ч. и в заголовке. Некоторые сервера и в теле письма с кодировками работают криво.
3. Следовательно, надо писать собственную программу отсылки сообщения.
4. Заголовок(тема) и тело письма кодируются в BASE64.
5. Кодировка определяется исходя из национальных настроек сервера.
6. Кодировка и способ передачи (например, ISO-8859-5+BASE64) в теме письма кодируются непосредственно, в теле письма, как было написано выше, полями заголовка content-transfer-encoding и charset.
7. Вооружённый этими знаниями, собираешь всё сообщение в виде переменной varchar2(32000) и отправляешь через utl_smtp.
8. Где-то у меня был готовый код, если интересно - пиши мылом <мой_ник>@<мой_ник>.com -- постараюсь найти.
15 июл 08, 14:20    [5936383]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
Спасибо, hardsign
16 июл 08, 04:02    [5939036]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
Когда уже не надеялся - нашлось готовое решение - по адресу:
http://tomachinsky.blogspot.com/2007_03_01_archive.html
в этой процедуре есь код, очень похожий (или такой же), как привёл Batsall.

Сам код (который находится по адресу (вышеприведённому)):

create or replace procedure sendmail(
s#sender in varchar2 := null,
s#recipient in varchar2,
s#subject in varchar2,
s#message in varchar2
)
is
c utl_smtp.connection;
s$message varchar2(1600) := s#message;
s$mailhost VARCHAR2(80) := '10.2.80.68'
;
s$sender varchar2(64) := 'test@server.ru';

FUNCTION MIMEHEADER_ENCODE(
s#string VARCHAR2) RETURN VARCHAR2
IS
BEGIN
RETURN '=?windows-1251?B?' || utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(convert(s#string, 'CL8MSWIN1251')))) || '?=';
END;

BEGIN
s$message := s#message||chr(10)||chr(10) || 'На это письмо отвечать не надо.' || CHR(10);
c := utl_smtp.open_connection(s$mailhost, 25);
utl_smtp.helo(c, s$mailhost);
utl_smtp.mail(c, s$sender);
utl_smtp.rcpt(c, s#recipient);
utl_smtp.open_data(c);
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw('From: '||convert('Тест<'||s$sender||'>', 'CL8MSWIN1251') || utl_tcp.CRLF));
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw('To: '||s#recipient||utl_tcp.CRLF));
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw('Subject: '|| MIMEHEADER_ENCODE(s#subject) || utl_tcp.CRLF));
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw('Content-Type: text/plain; charset="windows-1251"'||utl_tcp.CRLF));
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw(utl_tcp.CRLF||convert(s$message, 'CL8MSWIN1251')));
utl_smtp.close_data(c);
utl_smtp.quit(c);
EXCEPTION WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN
BEGIN
utl_smtp.quit(c);
EXCEPTION WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN NULL;
END;

raise_application_error(-20000, SQLERRM);
END;

это оригинальный код процедуры, которая мне помогла. Красным цветом в нём выделил места, которые у меня вызывали ошибки: ";" в коде по приведённой ссылке - нету, а нижняя строчка у меня материлась.


Далее этот же код, только я его немного переделал "под себя":

create or replace procedure sendmail(
s_sender in varchar2 := null,
s_recipient in varchar2,
s_subject in varchar2,
s_message in varchar2
)
is
c utl_smtp.connection;

-- s$message varchar2(1600) := s#message;
s_mailhost VARCHAR2(80) := '11.3.81.69'; --ip адрес немного вымышленный (например)
-- s$sender varchar2(64) := 'test@server.ru';

FUNCTION MIMEHEADER_ENCODE(
s_string VARCHAR2) RETURN VARCHAR2
IS
BEGIN
RETURN '=?windows-1251?B?' || utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(convert(s_string, 'CL8MSWIN1251')))) || '?=';
END;

BEGIN

-- s$message := s#message||chr(10)||chr(10) || 'На это письмо отвечать не надо.' || CHR(10);
c := utl_smtp.open_connection(s_mailhost, 25);
utl_smtp.helo(c, s_mailhost);
utl_smtp.mail(c, s_sender);
utl_smtp.rcpt(c, s_recipient);
utl_smtp.open_data(c);
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw('From: '||convert(s_sender, 'CL8MSWIN1251') || utl_tcp.CRLF));
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw('To: '||s_recipient||utl_tcp.CRLF));
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw('Subject: '|| MIMEHEADER_ENCODE(s_subject) || utl_tcp.CRLF));
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw('Content-Type: text/plain; charset="windows-1251"'||utl_tcp.CRLF));
utl_smtp.write_raw_data(c, utl_raw.cast_to_raw(utl_tcp.CRLF||convert(s_message, 'CL8MSWIN1251')));
utl_smtp.close_data(c);
utl_smtp.quit(c);
EXCEPTION WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN
BEGIN
utl_smtp.quit(c);
EXCEPTION WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN NULL;
END;

-- raise_application_error(-20000, SQLERRM);
END;


Этим, например, можно запускать:
call sendmail (
'...@yandex.ru',
'...@mail.ru',
'тема письма',
'текст письма - здравствуйте, досвидания.');
16 июл 08, 04:32    [5939042]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
Эта процедура решила все проблеммы с кодировками, сам, правда, не очень понимаю что там понаписано в некоторых местах - какая-то мешанина странных символов, вопросиков, значков, и всё это в одной куче с данными (непонимаю пока, как во всём этом разбирается обработчик кода?), но видимо разбирается, и работает у меня хорошо, и тема и тело письма везде русскими буквами.

Тестировал на:

...@gmail.com,
...@hotmail.com,
...@mail.ru,
...@yandex.ru,
в Outlook express и Lotus Notes

везде всё нормально.
16 июл 08, 04:40    [5939044]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
hardsign
Member

Откуда: Оттуда... Как оттуда???
Сообщений: 137
PSergeyA
Эта процедура решила все проблеммы с кодировками, сам, правда, не очень понимаю что там понаписано в некоторых местах


Правильная процедура :) Я вот в своё время поленился прочитать supplied packages reference, поэтому перекодировку в BASE64 писал самостоятельно, а вместо convert() определял текущую кодировку на сервере при помощи
select value from v$nls_parameters where parameter='NLS_CHARACTERSET'

А чтобы закорючки стали понятны, надо читать RFC на MIME-сообщения :)
16 июл 08, 09:29    [5939394]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
PSergeyA
Member

Откуда: Иркутск
Сообщений: 77
ну что ж,
спасибо, пригодится :)
как-нибудь, будет время, почитаю про эти закорючки )
18 июл 08, 06:07    [5951478]     Ответить | Цитировать Сообщить модератору
Между сообщениями интервал более 1 года.
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировк  [new]
pixela
Member

Откуда: Санкт-Петербург
Сообщений: 97
Batsall
Делаю так, вроде везде отображается
   
PROCEDURE   SEND_MAIL (
...
   s#subject     IN   VARCHAR2,
...
) IS
FUNCTION mimeheader_encode (s#string VARCHAR2)
      RETURN VARCHAR2
   IS
   BEGIN
      RETURN    '=?windows-1251?B?'
             || UTL_RAW.cast_to_varchar2
                   (UTL_ENCODE.base64_encode
                                 (UTL_RAW.cast_to_raw (CONVERT (s#string,
                                                                'CL8MSWIN1251'
                                                               )
                                                      )
                                 )
                   )
             || '?=';
   END;
...
BEGIN
...
UTL_SMTP.write_raw_data
                          (c,
                           UTL_RAW.cast_to_raw (   'Subject: '
                                                || mimeheader_encode
                                                                    (s#subject)
                                                || UTL_TCP.crlf
                                               )
                          );
...
END;


Работаю по такому алгоритму, и всё прекрасно работало пока не пришлось строку сабжа формировать динамически. Выяснилось, что при таком подходе строка сабжа не может быть более 47 символов.
Если больше 47 символов, то сабж превращается в такую строку:
=?windows-1251?B?0fLg8vPxIO/w7vHw7vfl7SAoIvHz7+Xw8fPv5fDx8+/l8PHz7+Xw8fPv5fDx8+/l

Никто не знает, как обойти это ограничение?
2 авг 10, 18:54    [9196338]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
-2-
Member

Откуда:
Сообщений: 15330
pixela,

Версия? utl_mail нормально кодирует и боди и сабжект.
2 авг 10, 19:07    [9196400]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
pixela
Member

Откуда: Санкт-Петербург
Сообщений: 97
-2-
pixela,
Версия? utl_mail нормально кодирует и боди и сабжект.


9.2.0.7
Я использую utl.smtp.
Все в порядке, если символов в сабже не более 47. Если больше, то коверкает строку сабжа (как я писал выше) и в боди добавляется тоже "мусор" вроде такого:
KQ0K?=
MIME-version: 1.0
Content-Type: multipart/mixed; boundary="-----7D81B75CCC90D2974F7A1CBD"

This is a multi-part message in MIME format.
-------7D81B75CCC90D2974F7A1CBD
Content-Type: text/plain; charset="Windows-1251"
Content-Transfer-Encoding: quoted-printable

и дальше "полезные" строки письма
3 авг 10, 13:38    [9199685]     Ответить | Цитировать Сообщить модератору
 Re: При отправки почты средствами utl_smtp на разных почт. серверах тема в разных кодировках  [new]
-2-
Member

Откуда:
Сообщений: 15330
pixela
Все в порядке, если символов в сабже не более 47. Если больше, то коверкает строку сабжа
rfc2822
2.2.3. Long Header Fields

Each header field is logically a single line of characters comprising
the field name, the colon, and the field body. For convenience
however, and to deal with the 998/78 character limitations per line,
the field body portion of a header field can be split into a multiple
line representation; this is called "folding". The general rule is

that wherever this standard allows for folding white space (not
simply WSP characters), a CRLF may be inserted before any WSP. For
example, the header field:

Subject: This is a test

can be represented as:

Subject: This
is a test

Note: Though structured field bodies are defined in such a way that
folding can take place between many of the lexical tokens (and even
within some of the lexical tokens), folding SHOULD be limited to
placing the CRLF at higher-level syntactic breaks. For instance, if
a field body is defined as comma-separated values, it is recommended
that folding occur after the comma separating the structured items in
preference to other places where the field could be folded, even if
it is allowed elsewhere.

The process of moving from this folded multiple-line representation
of a header field to its single line representation is called
"unfolding". Unfolding is accomplished by simply removing any CRLF
that is immediately followed by WSP. Each header field should be
treated in its unfolded form for further syntactic and semantic
evaluation.
Кодируйте в quoted-printable - там проще "предсказать" длину. И переносите.
3 авг 10, 13:45    [9199750]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить