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;