Procedure for sending mails
This commit is contained in:
parent
056b3bda88
commit
9bf82ae162
@ -32,6 +32,14 @@ CREATE OR REPLACE PACKAGE app_actions AS
|
|||||||
settings_package CONSTANT VARCHAR2(30) := 'SETT';
|
settings_package CONSTANT VARCHAR2(30) := 'SETT';
|
||||||
settings_prefix CONSTANT VARCHAR2(30) := 'get_';
|
settings_prefix CONSTANT VARCHAR2(30) := 'get_';
|
||||||
|
|
||||||
|
-- for sending emails
|
||||||
|
smtp_from CONSTANT VARCHAR2(200) := '';
|
||||||
|
smtp_username CONSTANT VARCHAR2(50) := NULL;
|
||||||
|
smtp_password CONSTANT VARCHAR2(50) := NULL;
|
||||||
|
smtp_host CONSTANT VARCHAR2(50) := '';
|
||||||
|
smtp_port CONSTANT NUMBER(4) := 25;
|
||||||
|
smtp_timeout CONSTANT NUMBER(2) := 20;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -235,5 +243,23 @@ CREATE OR REPLACE PACKAGE app_actions AS
|
|||||||
--
|
--
|
||||||
PROCEDURE refresh_user_source_views;
|
PROCEDURE refresh_user_source_views;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Send UTF_8 email with compressed attachements
|
||||||
|
--
|
||||||
|
PROCEDURE send_mail (
|
||||||
|
in_to VARCHAR2,
|
||||||
|
in_subject VARCHAR2,
|
||||||
|
in_body CLOB,
|
||||||
|
in_cc VARCHAR2 := NULL,
|
||||||
|
in_bcc VARCHAR2 := NULL,
|
||||||
|
in_from VARCHAR2 := NULL,
|
||||||
|
in_attach_name VARCHAR2 := NULL,
|
||||||
|
in_attach_mime VARCHAR2 := NULL,
|
||||||
|
in_attach_data CLOB := NULL,
|
||||||
|
in_compress BOOLEAN := FALSE
|
||||||
|
);
|
||||||
|
|
||||||
END;
|
END;
|
||||||
/
|
/
|
||||||
|
|||||||
@ -816,5 +816,195 @@ CREATE OR REPLACE PACKAGE BODY app_actions AS
|
|||||||
app.raise_error();
|
app.raise_error();
|
||||||
END;
|
END;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PROCEDURE send_mail (
|
||||||
|
in_to VARCHAR2,
|
||||||
|
in_subject VARCHAR2,
|
||||||
|
in_body CLOB,
|
||||||
|
in_cc VARCHAR2 := NULL,
|
||||||
|
in_bcc VARCHAR2 := NULL,
|
||||||
|
in_from VARCHAR2 := NULL,
|
||||||
|
in_attach_name VARCHAR2 := NULL,
|
||||||
|
in_attach_mime VARCHAR2 := NULL,
|
||||||
|
in_attach_data CLOB := NULL,
|
||||||
|
in_compress BOOLEAN := FALSE
|
||||||
|
) AS
|
||||||
|
boundary CONSTANT VARCHAR2(80) := '-----5b9d8059445a8eb8c025f159131f02d94969a12c16363d4dec42e893b374cb85-----';
|
||||||
|
--
|
||||||
|
reply UTL_SMTP.REPLY;
|
||||||
|
conn UTL_SMTP.CONNECTION;
|
||||||
|
--
|
||||||
|
blob_content BLOB;
|
||||||
|
blob_gzipped BLOB;
|
||||||
|
blob_amount BINARY_INTEGER := 6000;
|
||||||
|
blob_offset PLS_INTEGER := 1;
|
||||||
|
buffer VARCHAR2(24000);
|
||||||
|
buffer_raw RAW(6000);
|
||||||
|
--
|
||||||
|
FUNCTION quote_encoding (
|
||||||
|
in_text VARCHAR2
|
||||||
|
)
|
||||||
|
RETURN VARCHAR2 AS
|
||||||
|
BEGIN
|
||||||
|
RETURN '=?UTF-8?Q?' || REPLACE(
|
||||||
|
UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.QUOTED_PRINTABLE_ENCODE(
|
||||||
|
UTL_RAW.CAST_TO_RAW(in_text))), '=' || UTL_TCP.CRLF, '') || '?=';
|
||||||
|
END;
|
||||||
|
--
|
||||||
|
FUNCTION quote_address (
|
||||||
|
in_address VARCHAR2,
|
||||||
|
in_strip_name BOOLEAN := FALSE
|
||||||
|
)
|
||||||
|
RETURN VARCHAR2 AS
|
||||||
|
in_found PLS_INTEGER;
|
||||||
|
BEGIN
|
||||||
|
IF in_strip_name THEN
|
||||||
|
RETURN REGEXP_REPLACE(in_address, '.*\s?<(\S+)>$', '\1');
|
||||||
|
ELSE
|
||||||
|
in_found := REGEXP_INSTR(in_address, '\s?<\S+@\S+\.\S{2,6}>$');
|
||||||
|
IF in_found > 1 THEN
|
||||||
|
RETURN quote_encoding(RTRIM(SUBSTR(in_address, 1, in_found))) || SUBSTR(in_address, in_found);
|
||||||
|
ELSE
|
||||||
|
RETURN in_address;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
END;
|
||||||
|
--
|
||||||
|
FUNCTION clob_to_blob (
|
||||||
|
in_clob CLOB
|
||||||
|
)
|
||||||
|
RETURN BLOB AS
|
||||||
|
out_blob BLOB;
|
||||||
|
--
|
||||||
|
v_file_size INTEGER := DBMS_LOB.LOBMAXSIZE;
|
||||||
|
v_dest_offset INTEGER := 1;
|
||||||
|
v_src_offset INTEGER := 1;
|
||||||
|
v_blob_csid NUMBER := DBMS_LOB.DEFAULT_CSID;
|
||||||
|
v_lang_context NUMBER := DBMS_LOB.DEFAULT_LANG_CTX;
|
||||||
|
v_warning INTEGER;
|
||||||
|
v_length NUMBER;
|
||||||
|
BEGIN
|
||||||
|
DBMS_LOB.CREATETEMPORARY(out_blob, TRUE);
|
||||||
|
DBMS_LOB.CONVERTTOBLOB(out_blob, in_clob, v_file_size, v_dest_offset, v_src_offset, v_blob_csid, v_lang_context, v_warning);
|
||||||
|
RETURN out_blob;
|
||||||
|
END;
|
||||||
|
--
|
||||||
|
PROCEDURE split_addresses (
|
||||||
|
in_out_conn IN OUT NOCOPY UTL_SMTP.CONNECTION,
|
||||||
|
in_to IN VARCHAR2
|
||||||
|
)
|
||||||
|
AS
|
||||||
|
BEGIN
|
||||||
|
FOR i IN (
|
||||||
|
SELECT LTRIM(RTRIM(REGEXP_SUBSTR(in_to, '[^;,]+', 1, LEVEL))) AS address
|
||||||
|
FROM DUAL
|
||||||
|
CONNECT BY REGEXP_SUBSTR(in_to, '[^;,]+', 1, LEVEL) IS NOT NULL)
|
||||||
|
LOOP
|
||||||
|
UTL_SMTP.RCPT(in_out_conn, quote_address(i.address, TRUE));
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
BEGIN
|
||||||
|
app.log_module(in_to, in_subject, in_cc, in_bcc, in_attach_name);
|
||||||
|
|
||||||
|
-- connect to SMTP server
|
||||||
|
reply := UTL_SMTP.OPEN_CONNECTION(smtp_host, smtp_port, conn, smtp_timeout);
|
||||||
|
UTL_SMTP.HELO(conn, smtp_host);
|
||||||
|
IF smtp_username IS NOT NULL THEN
|
||||||
|
UTL_SMTP.COMMAND(conn, 'AUTH LOGIN');
|
||||||
|
UTL_SMTP.COMMAND(conn, UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(smtp_username)));
|
||||||
|
IF smtp_password IS NOT NULL THEN
|
||||||
|
UTL_SMTP.COMMAND(conn, UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(smtp_password)));
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- prepare headers
|
||||||
|
UTL_SMTP.MAIL(conn, quote_address(COALESCE(in_from, smtp_from), TRUE));
|
||||||
|
|
||||||
|
-- handle multiple recipients
|
||||||
|
split_addresses(conn, in_to);
|
||||||
|
--
|
||||||
|
IF in_cc IS NOT NULL THEN
|
||||||
|
split_addresses(conn, in_cc);
|
||||||
|
END IF;
|
||||||
|
--
|
||||||
|
IF in_bcc IS NOT NULL THEN
|
||||||
|
split_addresses(conn, in_bcc);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- continue with headers
|
||||||
|
UTL_SMTP.OPEN_DATA(conn);
|
||||||
|
--
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Date: ' || TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'From: ' || quote_address(COALESCE(in_from, smtp_from)) || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'To: ' || quote_address(in_to) || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Subject: ' || quote_encoding(in_subject) || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Reply-To: ' || in_from || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'MIME-Version: 1.0' || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Type: multipart/mixed; boundary="' || boundary || '"' || UTL_TCP.CRLF || UTL_TCP.CRLF);
|
||||||
|
|
||||||
|
-- prepare body content
|
||||||
|
IF in_body IS NOT NULL THEN
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, '--' || boundary || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Type: ' || 'text/html' || '; charset="utf-8"' || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Transfer-Encoding: base64' || UTL_TCP.CRLF || UTL_TCP.CRLF);
|
||||||
|
--
|
||||||
|
FOR i IN 0 .. TRUNC((DBMS_LOB.GETLENGTH(in_body) - 1) / 12000) LOOP
|
||||||
|
UTL_SMTP.WRITE_RAW_DATA(conn, UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(in_body, 12000, i * 12000 + 1))));
|
||||||
|
END LOOP;
|
||||||
|
--
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, UTL_TCP.CRLF || UTL_TCP.CRLF);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- prepare attachment
|
||||||
|
IF in_attach_name IS NOT NULL AND in_compress THEN
|
||||||
|
-- compress attachment
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, '--' || boundary || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Transfer-Encoding: base64' || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Type: ' || 'application/octet-stream' || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Disposition: attachment; filename="' || in_attach_name || '.gz"' || UTL_TCP.CRLF || UTL_TCP.CRLF);
|
||||||
|
--
|
||||||
|
blob_content := clob_to_blob(in_attach_data);
|
||||||
|
DBMS_LOB.CREATETEMPORARY(blob_gzipped, TRUE, DBMS_LOB.CALL);
|
||||||
|
DBMS_LOB.OPEN(blob_gzipped, DBMS_LOB.LOB_READWRITE);
|
||||||
|
--
|
||||||
|
UTL_COMPRESS.LZ_COMPRESS(blob_content, blob_gzipped, quality => 8);
|
||||||
|
--
|
||||||
|
WHILE blob_offset <= DBMS_LOB.GETLENGTH(blob_gzipped) LOOP
|
||||||
|
DBMS_LOB.READ(blob_gzipped, blob_amount, blob_offset, buffer_raw);
|
||||||
|
UTL_SMTP.WRITE_RAW_DATA(conn, UTL_ENCODE.BASE64_ENCODE(buffer_raw));
|
||||||
|
blob_offset := blob_offset + blob_amount;
|
||||||
|
END LOOP;
|
||||||
|
DBMS_LOB.FREETEMPORARY(blob_gzipped);
|
||||||
|
--
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, UTL_TCP.CRLF || UTL_TCP.CRLF);
|
||||||
|
ELSIF in_attach_name IS NOT NULL THEN
|
||||||
|
-- regular attachment
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, '--' || boundary || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Transfer-Encoding: base64' || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Type: ' || in_attach_mime || '; name="' || in_attach_name || '"' || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, 'Content-Disposition: attachment; filename="' || in_attach_name || '"' || UTL_TCP.CRLF || UTL_TCP.CRLF);
|
||||||
|
--
|
||||||
|
FOR i IN 0 .. TRUNC((DBMS_LOB.GETLENGTH(in_attach_data) - 1) / 12000) LOOP
|
||||||
|
UTL_SMTP.WRITE_RAW_DATA(conn, UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(DBMS_LOB.SUBSTR(in_attach_data, 12000, i * 12000 + 1))));
|
||||||
|
END LOOP;
|
||||||
|
--
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, UTL_TCP.CRLF || UTL_TCP.CRLF);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- close
|
||||||
|
UTL_SMTP.WRITE_DATA(conn, '--' || boundary || '--' || UTL_TCP.CRLF);
|
||||||
|
UTL_SMTP.CLOSE_DATA(conn);
|
||||||
|
UTL_SMTP.QUIT(conn);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN UTL_SMTP.TRANSIENT_ERROR OR UTL_SMTP.PERMANENT_ERROR THEN
|
||||||
|
BEGIN
|
||||||
|
UTL_SMTP.QUIT(conn);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN UTL_SMTP.TRANSIENT_ERROR OR UTL_SMTP.PERMANENT_ERROR THEN
|
||||||
|
NULL;
|
||||||
|
END;
|
||||||
|
END;
|
||||||
|
|
||||||
END;
|
END;
|
||||||
/
|
/
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user