Hogyan küldhetünk Oracle-ből utf8 tárgyú és szövegű emailt több címzettnek? Nem nehéz, csak az utl_smtp csomagot kell ismerni, és írni kell egy split string eljárást, mert az nincs a PL/SQL-ben. A szöveget QP kódolással alakítjuk ASCII-vá.
Itt egyszerűsítésként minden egyetlen önálló eljárásba került, de persze szerencsésebb, ha standalone és nested szubrutinok helyett csomagokba szervezzük a kódunkat.
create or replace
procedure send_utf8_mail(
p_to varchar2,
p_from varchar2,
p_subject varchar2,
p_message varchar2
)
as
c_smtp_host constant varchar2(255) := 'smtp.example.com';
c_smtp_port constant pls_integer := 25; -- or 587
l_conn utl_smtp.connection;
-- utf8 + qp encoding
function encode(p_str varchar2) return varchar2
as
l_returnval varchar2(32767);
begin
l_returnval := convert(p_str, 'AL32UTF8');
l_returnval := utl_encode.quoted_printable_encode(utl_raw.cast_to_raw(l_returnval));
return l_returnval;
end encode;
-- split comma-separated emails, add recipients
procedure rcpt(p_conn in out nocopy utl_smtp.connection, p_str varchar2)
as
begin
for line_rec in (
select field
from (
select regexp_substr(line, '([^, ]+)', 1, level, null, 1) as field
from (select p_str as line from dual)
connect by level <= regexp_count(line, ',') + 1
)
where field is not null
)
loop
utl_smtp.rcpt(p_conn, line_rec.field);
end loop;
end rcpt;
begin
l_conn := utl_smtp.open_connection(c_smtp_host, c_smtp_port);
utl_smtp.helo(l_conn, c_smtp_host);
-- in case of TLS and/or authentication:
-- utl_smtp.ehlo(l_conn, c_smtp_host);
-- utl_smtp.starttls(l_conn);
-- utl_smtp.auth(l_conn, 'username', 'password', utl_smtp.all_schemes);
utl_smtp.mail(l_conn, p_from);
rcpt(l_conn, p_to);
utl_smtp.open_data(l_conn);
utl_smtp.write_data(l_conn, 'Subject: =?UTF-8?Q?' || utl_raw.cast_to_varchar2(encode(p_subject)) || '?=' || utl_tcp.crlf);
utl_smtp.write_data(l_conn, 'Date: ' || to_char(systimestamp, 'Dy, DD Mon YYYY HH24:MI:SS TZHTZM', 'nls_date_language=english') || utl_tcp.crlf);
utl_smtp.write_data(l_conn, 'From: ' || p_from || utl_tcp.crlf);
utl_smtp.write_data(l_conn, 'To: ' || p_to || utl_tcp.crlf);
utl_smtp.write_data(l_conn, 'MIME-version: 1.0' || utl_tcp.crlf);
utl_smtp.write_data(l_conn, 'Content-Type: text/plain;charset=utf-8"' || utl_tcp.crlf);
utl_smtp.write_data(l_conn, 'Content-Transfer-Encoding: quoted-printable' || utl_tcp.crlf);
utl_smtp.write_data(l_conn, utl_tcp.crlf);
utl_smtp.write_raw_data(l_conn, encode(p_message));
utl_smtp.write_data(l_conn, utl_tcp.crlf);
utl_smtp.close_data(l_conn);
utl_smtp.quit(l_conn);
end send_utf8_mail;
Az emailküldés egyrészt lassúnak számító művelet, másrészt hibát dobhat. Nyilván el tudjuk kapni az SMTP hibát, de a gyakorlatban ritkán akarjuk; azt pedig végképp nem akarjuk, hogy egy hosszú és sikeres programfutás sikertelenül fejeződjön be SMTP hiba miatt. Ezért érdemes lehet aszinkron módon meghívni a fenti eljárást, ami szintén könnyen megoldható egy csomagoló eljárással:
create or replace
procedure send_utf8_mail_async(
p_to varchar2,
p_from varchar2,
p_subject varchar2,
p_message varchar2
)
as
c_job_name constant varchar2(255) := dbms_scheduler.generate_job_name('mail');
begin
dbms_scheduler.create_job(
job_name => c_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'send_utf8_mail',
number_of_arguments => 4,
start_date => sysdate,
enabled => false,
auto_drop => true
);
dbms_scheduler.set_job_argument_value(
job_name => c_job_name,
argument_position => 1,
argument_value => p_to
);
dbms_scheduler.set_job_argument_value(
job_name => c_job_name,
argument_position => 2,
argument_value => p_from
);
dbms_scheduler.set_job_argument_value(
job_name => c_job_name,
argument_position => 3,
argument_value => p_subject
);
dbms_scheduler.set_job_argument_value(
job_name => c_job_name,
argument_position => 4,
argument_value => p_message
);
dbms_scheduler.enable(c_job_name);
end send_utf8_mail_async;