Read files using PLSQL from Multipart/Form-data in POST ORDS - oracle

I have an ORDS POST API where the front end developer will send 2 pdf files in multipart/form-data. I then have to send email with two pdf attachments using UTL_SMTP. I am on Oracle 12.1
I have the below utl smtp proc which can attach blobs in email from a table and it works fine by calling multiple times.But, I am not able to make it work when I have to read the files coming from multipart/form-data in POST API.
How should I read the form-data files?
....
...
PROCEDURE multiple_attachment( p_conn IN OUT utl_smtp.connection
,p_boundary IN VARCHAR2
,p_FileName IN VARCHAR2
,p_FileData IN BLOB)
AS
l_len integer := 0 ;
l_idx integer := 1 ;
l_buff_size integer := 57 ;
l_raw raw(57) ;
BEGIN
-- Attachment
utl_smtp.write_data( p_conn, '--' || p_boundary || utl_tcp.crlf );
utl_smtp.write_data( p_conn, 'Content-Type: application/pdf' || utl_tcp.crlf );
utl_smtp.write_data( p_conn, 'Content-Disposition: attachment; ' || utl_tcp.crlf );
utl_smtp.write_data( p_conn, ' filename="' || p_FileName || '"' || utl_tcp.crlf );
utl_smtp.write_data( p_conn, 'Content-Transfer-Encoding: base64' || utl_tcp.crlf );
utl_smtp.write_data( p_conn, utl_tcp.crlf );
l_len := dbms_lob.getlength(p_FileData);
l_buff_size := 57 ;
l_idx := 1;
WHILE l_idx < l_len LOOP
dbms_lob.read( p_FileData , l_buff_size, l_idx, l_raw );
utl_smtp.write_raw_data( p_conn, utl_encode.base64_encode(l_raw) );
utl_smtp.write_data( p_conn, utl_tcp.crlf );
l_idx := l_idx + l_buff_size;
END LOOP;
END;
UTL_SMTP.write_data(l_mail_conn, '--' || l_boundary || '--' || UTL_TCP.crlf);
UTL_SMTP.close_data(l_mail_conn);
....
...

Related

Unable to send attachment through PL/SQL for multiple lines inside attachment using UTL_SMTP

Can someone help me with UTL_SMTP.WRITE_DATA for sending email with attachment. I am not able to send attachment with multiple lines inside code.
When I write UTL_SMTP.WRITE_DATA to write data inside attachment it doesn't work.
Below is the attached code which sends attachment for only 1 row from second cursor when i=1.
Someone please help.
CREATE OR REPLACE PACKAGE BODY xx_common_alerts_pkg AS
gv_process_name CONSTANT VARCHAR2(100) := 'Common Alert Functionality';
PROCEDURE main (
po_errbuf OUT VARCHAR2,
po_retcode OUT NUMBER,
-- p_debug IN NUMBER,
p_alert_name IN VARCHAR2
) IS
lv_procedure CONSTANT VARCHAR2(200) := 'XX_COMMON_ALERTS_PKG.main';
lv_to_recipients alr_actions.to_recipients%TYPE;
lv_cc_recipients alr_actions.cc_recipients%TYPE;
lv_bcc_recipients alr_actions.bcc_recipients%TYPE;
lv_subject alr_actions.subject%TYPE;
lv_alert_id alr_alerts.alert_id%TYPE;
lv_row_count alr_action_set_checks.row_count%TYPE;
lv_check_id alr_action_set_checks.alert_check_id%TYPE;
v_clob CLOB := empty_clob();
v_clob_lines CLOB := empty_clob();
lv_mail_body_lines VARCHAR2(30000);
lv_ctxh dbms_xmlgen.ctxhandle;
lv_queryresult XMLTYPE;
lv_xslt_transform XMLTYPE;
lv_message VARCHAR2(30000);
lv_error_msg VARCHAR2(3000);
lv_inst_name VARCHAR2(50);
lv_from_email VARCHAR2(100);
lv_to_email VARCHAR2(100);
lv_recipients_mail VARCHAR2(100);
lv_status VARCHAR2(30000);
lv_alert_check_id VARCHAR2(2000);
lv_list_id alr_actions.list_id%TYPE;
lv_list_application_id alr_actions.list_application_id%TYPE;
lv_body alr_actions.body%TYPE;
lv_ret_message VARCHAR2(2000);
lv_ret_status VARCHAR2(2000);
lv_attach_tab t_attach_tab := t_attach_tab();
v_from VARCHAR2(80) := 'abc#gmail.com';
v_recipient VARCHAR2(80) := 'def#gmail.com';
v_subject VARCHAR2(80) := 'test';
v_mail_host VARCHAR2(80) := 'mlocalhost'; --localhost';
v_smtp_port NUMBER := 25;
v_mail_conn utl_smtp.connection;
l_step PLS_INTEGER := 12000;
crlf VARCHAR2(2) := chr(13)
|| chr(10);
v_len INTEGER;
v_index INTEGER := 1;
le_mail_excp EXCEPTION;
CURSOR c_get_alert_outputs (
pi_alert_id VARCHAR2
) IS
SELECT
name,
title
FROM
alr_alert_outputs
WHERE
alert_id = pi_alert_id
AND end_date_active IS NULL
ORDER BY
name DESC;
CURSOR c_output_lines (
pi_check_id NUMBER,
pi_row_number NUMBER
) IS
SELECT DISTINCT
value,
name
FROM
alr_output_history
WHERE
check_id = pi_check_id
AND row_number = pi_row_number
ORDER BY
name DESC;
BEGIN
SELECT
actions.to_recipients,
actions.cc_recipients,
actions.bcc_recipients,
actions.subject,
alr.alert_id,
actions.list_id,
actions.list_application_id,
actions.body
INTO
lv_to_recipients,
lv_cc_recipients,
lv_bcc_recipients,
lv_subject,
lv_alert_id,
lv_list_id,
lv_list_application_id,
lv_body
FROM
alr_alerts alr,
alr_actions actions
WHERE
alr.alert_name = p_alert_name
AND alr.alert_id = actions.alert_id
AND actions.name = 'Send Email'
AND actions.enabled_flag = 'Y'
AND actions.end_date_active IS NULL;
IF lv_list_id IS NOT NULL THEN
SELECT
to_recipients,
cc_recipients,
bcc_recipients
INTO
lv_to_recipients,
lv_cc_recipients,
lv_bcc_recipients
FROM
alr_distribution_lists
WHERE
list_id = lv_list_id
AND application_id = lv_list_application_id
AND enabled_flag = 'Y'
AND end_date_active IS NULL;
END IF;
SELECT
row_count,
check_id,
alert_check_id
INTO
lv_row_count,
lv_check_id,
lv_alert_check_id
FROM
alr_action_set_checks
WHERE
alert_id = lv_alert_id
AND alert_check_id = (
SELECT
MAX(alert_check_id)
FROM
alr_action_set_checks
WHERE
alert_id = lv_alert_id
);
-- lv_attach_tab.DELETE;
v_mail_conn := utl_smtp.open_connection(v_mail_host, 25);
utl_smtp.helo(v_mail_conn, v_mail_host);
utl_smtp.mail(v_mail_conn, v_from);
utl_smtp.rcpt(v_mail_conn, v_recipient);
FOR rec_alert_outputs IN c_get_alert_outputs(lv_alert_id) LOOP
v_clob := rec_alert_outputs.title
|| ','
|| v_clob;
END LOOP;
FOR i IN 1..lv_row_count LOOP
v_clob_lines := empty_clob();
FOR rec_lines IN c_output_lines(lv_check_id, i) LOOP
v_clob_lines := rec_lines.value
|| ','
|| v_clob_lines;
END LOOP;
utl_smtp.data(v_mail_conn, 'Date: '
|| TO_CHAR(SYSDATE, 'Dy, DD Mon YYYY hh24:mi:ss')
|| crlf
|| 'From: '
|| v_from
|| crlf
|| 'Subject: '
|| v_subject
|| crlf
|| 'To: '
|| v_recipient
|| crlf
|| 'MIME-Version: 1.0'
|| crlf
|| -- Use MIME mail standard
'Content-Type: multipart/mixed;'
|| crlf
|| ' boundary="-----SECBOUND"'
|| crlf
|| crlf
|| '-------SECBOUND'
|| crlf
|| 'Content-Type: text/plain;'
|| crlf
|| 'Content-Transfer_Encoding: 7bit'
|| crlf
|| crlf
|| lv_body
|| crlf
|| crlf
|| '-------SECBOUND'
|| crlf
|| 'Content-Type: text/plain;'
|| crlf
|| ' name="ASL_Mismatch.csv"'
|| crlf
|| 'Content-Transfer_Encoding: 8bit'
|| crlf
|| 'Content-Disposition: attachment;'
|| crlf
|| ' filename="Mismatch.csv"'
|| crlf
|| crlf
|| v_clob
|| crlf
|| v_clob_lines
|| crlf);
fnd_file.put_line(fnd_file.output, 'v_clob ' || v_clob);
utl_smtp.data(v_mail_conn, v_clob);
utl_smtp.data(v_mail_conn, v_clob_lines);
--UTL_SMTP.write_data(v_Mail_Conn, UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(DBMS_LOB.substr(v_clob_lines, 1, i * 1))) || UTL_TCP.crlf);
--UTL_SMTP.write_data(v_Mail_Conn,UTL_RAW.cast_to_varchar2(v_clob_lines));
-- utl_smtp.write_data(v_Mail_Conn, v_clob_lines);
-- UTL_SMTP.write_data(v_Mail_Conn, DBMS_LOB.SUBSTR(v_clob_lines, 32000, v_index));
fnd_file.put_line(fnd_file.output, 'v_clob_lines '
|| v_clob_lines
|| ' Row: '
|| i);
END LOOP;
utl_smtp.write_data(v_mail_conn, utl_tcp.crlf);
utl_smtp.write_data(v_mail_conn, '--'
|| ' boundary="-----SECBOUND"'
|| '--'
|| utl_tcp.crlf);
utl_smtp.close_data(v_mail_conn);
utl_smtp.quit(v_mail_conn);
EXCEPTION
WHEN OTHERS THEN
lv_error_msg := p_alert_name
|| '-'
|| lv_status
|| ': '
|| sqlerrm;
--debug(pi_message => lv_error_msg
-- );
END main;
END xx_common_alerts_pkg;
Rather than try to debug your code, I'll share with you my own sendmail function and you can use it to figure out what you're doing wrong. One difference that stands out to me immediately is I'm using base64 encoding rather than 8-bit, to prevent anything in the attachment from messing up SMTP. I'm sure there are multiple ways to do it, but this has been working for me for many years:
CREATE OR REPLACE PROCEDURE sendmail_html(sender_email IN varchar2,
recipient_email IN varchar2,
message_in IN clob,
subject_in IN varchar2 := NULL,
sender_name IN varchar2 :=NULL,
recipient_name IN varchar2 := NULL,
attachment_name_1 IN varchar2 := NULL,
attachment_mime_1 IN varchar2 := NULL,
attachment_clob_1 IN clob := NULL,
attachment_name_2 IN varchar2 := NULL,
attachment_mime_2 IN varchar2 := NULL,
attachment_clob_2 IN clob := NULL,
attachment_name_3 IN varchar2 := NULL,
attachment_mime_3 IN varchar2 := NULL,
attachment_clob_3 IN clob := NULL,
attachment_name_4 IN varchar2 := NULL,
attachment_mime_4 IN varchar2 := NULL,
attachment_clob_4 IN clob := NULL,
attachment_name_5 IN varchar2 := NULL,
attachment_mime_5 IN varchar2 := NULL,
attachment_clob_5 IN clob := NULL)
AS
PRAGMA AUTONOMOUS_TRANSACTION;
mail_host varchar2(30) := 'localhost';
mail_connection utl_smtp.connection;
message clob;
message_piece varchar2(2000);
boundary VARCHAR2(50) := '----=*#abc1234321cba#*=';
step PLS_INTEGER := 12000; -- make sure you set a multiple of 3 not higher than 24573
var_start_pos integer;
var_unencoded_raw raw(32767);
var_encoded_raw raw(32767);
var_encoded_string varchar2(32767);
BEGIN
message := message_in;
mail_connection := utl_smtp.open_connection(mail_host, 25);
utl_smtp.helo(mail_connection, mail_host);
utl_smtp.mail(mail_connection, sender_email);
utl_smtp.rcpt(mail_connection, recipient_email);
utl_smtp.open_data(mail_connection);
utl_smtp.write_data(mail_connection,'Date: '||TO_CHAR(SYSDATE,'dd Mon yy hh24:mi:ss')||utl_tcp.CRLF);
utl_smtp.write_data(mail_connection,'From: '||NVL(sender_name,sender_email)||' <'||sender_email||'>'||utl_tcp.CRLF);
utl_smtp.write_data(mail_connection,'To: '||NVL(recipient_name,recipient_email)||' <'||recipient_email||'>'||utl_tcp.CRLF);
utl_smtp.write_data(mail_connection,'Subject: '||NVL(subject_in,' ')|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'MIME-Version: 1.0' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Type: multipart/mixed; boundary="' || boundary || '"' || utl_tcp.CRLF || utl_tcp.CRLF);
IF dbms_lob.getlength(message) > 0
THEN
utl_smtp.write_data(mail_connection, '--' || boundary || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Type: text/html; charset=us-ascii ' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Disposition: inline' || utl_tcp.CRLF || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '<html>'|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '<head>'|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '<title>'||NVL(subject_in,' ')||'</title>'|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '</head>'|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '<body>'|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '<pre style="font: monospace">'|| utl_tcp.CRLF);
FOR chunk IN 1..CEIL(dbms_lob.getlength(message)/1000)
LOOP
var_start_pos := 1+(chunk-1)*1000;
utl_smtp.write_data(mail_connection,dbms_lob.substr(message,1000,var_start_pos));
END LOOP;
utl_smtp.write_data(mail_connection, '</pre>'|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '</body>'|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '</html>'|| utl_tcp.CRLF);
utl_smtp.write_data(mail_connection,utl_tcp.CRLF||utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, '--' || boundary || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Type: text/plain; charset="iso-8859-1"; format=flowed' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Disposition: inline' || utl_tcp.CRLF || utl_tcp.CRLF);
FOR chunk IN 1..CEIL(dbms_lob.getlength(message)/1000)
LOOP
var_start_pos := 1+(chunk-1)*1000;
utl_smtp.write_data(mail_connection,dbms_lob.substr(message,1000,var_start_pos));
END LOOP;
utl_smtp.write_data(mail_connection,utl_tcp.CRLF||utl_tcp.CRLF);
END IF;
IF LENGTH(attachment_clob_1) > 0
THEN
utl_smtp.write_data(mail_connection, '--' || boundary || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Type: ' || attachment_mime_1 || '; name="' || attachment_name_1 || '"' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Transfer-Encoding: base64' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Disposition: attachment; filename="' || attachment_name_1 || '"' || utl_tcp.CRLF || utl_tcp.CRLF);
FOR i IN 0 .. TRUNC((dbms_lob.getlength(attachment_clob_1) - 1 )/step)
LOOP
var_unencoded_raw := utl_raw.cast_to_raw(dbms_lob.substr(attachment_clob_1, step, i * step + 1));
var_encoded_raw := utl_encode.base64_encode(var_unencoded_raw);
var_encoded_string := utl_raw.cast_to_varchar2(var_encoded_raw);
utl_smtp.write_data(mail_connection, var_encoded_string);
END LOOP;
utl_smtp.write_data(mail_connection, utl_tcp.CRLF || utl_tcp.CRLF);
END IF;
IF LENGTH(attachment_clob_2) > 0
THEN
utl_smtp.write_data(mail_connection, '--' || boundary || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Type: ' || attachment_mime_2 || '; name="' || attachment_name_2 || '"' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Transfer-Encoding: base64' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Disposition: attachment; filename="' || attachment_name_2 || '"' || utl_tcp.CRLF || utl_tcp.CRLF);
FOR i IN 0 .. TRUNC((dbms_lob.getlength(attachment_clob_2) - 1 )/step)
LOOP
var_unencoded_raw := utl_raw.cast_to_raw(dbms_lob.substr(attachment_clob_2, step, i * step + 1));
var_encoded_raw := utl_encode.base64_encode(var_unencoded_raw);
var_encoded_string := utl_raw.cast_to_varchar2(var_encoded_raw);
utl_smtp.write_data(mail_connection, var_encoded_string);
END LOOP;
utl_smtp.write_data(mail_connection, utl_tcp.CRLF || utl_tcp.CRLF);
END IF;
IF LENGTH(attachment_clob_3) > 0
THEN
utl_smtp.write_data(mail_connection, '--' || boundary || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Type: ' || attachment_mime_3 || '; name="' || attachment_name_3 || '"' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Transfer-Encoding: base64' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Disposition: attachment; filename="' || attachment_name_3 || '"' || utl_tcp.CRLF || utl_tcp.CRLF);
FOR i IN 0 .. TRUNC((dbms_lob.getlength(attachment_clob_3) - 1 )/step)
LOOP
var_unencoded_raw := utl_raw.cast_to_raw(dbms_lob.substr(attachment_clob_3, step, i * step + 1));
var_encoded_raw := utl_encode.base64_encode(var_unencoded_raw);
var_encoded_string := utl_raw.cast_to_varchar2(var_encoded_raw);
utl_smtp.write_data(mail_connection, var_encoded_string);
END LOOP;
utl_smtp.write_data(mail_connection, utl_tcp.CRLF || utl_tcp.CRLF);
END IF;
IF LENGTH(attachment_clob_4) > 0
THEN
utl_smtp.write_data(mail_connection, '--' || boundary || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Type: ' || attachment_mime_4 || '; name="' || attachment_name_4 || '"' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Transfer-Encoding: base64' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Disposition: attachment; filename="' || attachment_name_4 || '"' || utl_tcp.CRLF || utl_tcp.CRLF);
FOR i IN 0 .. TRUNC((dbms_lob.getlength(attachment_clob_4) - 1 )/step)
LOOP
var_unencoded_raw := utl_raw.cast_to_raw(dbms_lob.substr(attachment_clob_4, step, i * step + 1));
var_encoded_raw := utl_encode.base64_encode(var_unencoded_raw);
var_encoded_string := utl_raw.cast_to_varchar2(var_encoded_raw);
utl_smtp.write_data(mail_connection, var_encoded_string);
END LOOP;
utl_smtp.write_data(mail_connection, utl_tcp.CRLF || utl_tcp.CRLF);
END IF;
IF LENGTH(attachment_clob_5) > 0
THEN
utl_smtp.write_data(mail_connection, '--' || boundary || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Type: ' || attachment_mime_5 || '; name="' || attachment_name_5 || '"' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Transfer-Encoding: base64' || utl_tcp.CRLF);
utl_smtp.write_data(mail_connection, 'Content-Disposition: attachment; filename="' || attachment_name_5 || '"' || utl_tcp.CRLF || utl_tcp.CRLF);
FOR i IN 0 .. TRUNC((dbms_lob.getlength(attachment_clob_5) - 1 )/step)
LOOP
var_unencoded_raw := utl_raw.cast_to_raw(dbms_lob.substr(attachment_clob_5, step, i * step + 1));
var_encoded_raw := utl_encode.base64_encode(var_unencoded_raw);
var_encoded_string := utl_raw.cast_to_varchar2(var_encoded_raw);
utl_smtp.write_data(mail_connection, var_encoded_string);
END LOOP;
utl_smtp.write_data(mail_connection, utl_tcp.CRLF || utl_tcp.CRLF);
END IF;
utl_smtp.write_data(mail_connection, '--' || boundary || '--' || utl_tcp.crlf);
utl_smtp.close_data(mail_connection);
utl_smtp.quit(mail_connection);
END;
/
This is HTML enabled in the body. I have another one that is plain text. I like having HTML so I can do some simple formatting like bold and italics and such.
My attachments however tend to be text, even if CSV or XML intended for Excel. So, I always use the mime 'text/plain' for my attachments. Compile your attachment as a CLOB and pass it into one of the attachment parameters.

utl_smtp send 1kb image attachment

I need to send a html message and also attach one specific image for that. Already did the html message part and now I still need to send that image to email but i only get 1kb attachment.
I really can't understand what I'm doing wrong. Tried lots of methods and I can't figure out.
Any idea can help me please. Thank you!
a and b are just masked values, I'm not using it like this.
create or replace procedure send_html_utl_mail(p_from IN VARCHAR2,
p_to IN VARCHAR2,
p_cc IN VARCHAR2 default null,
p_subject IN VARCHAR2,
p_body IN VARCHAR2,
p_attach_name IN VARCHAR2 DEFAULT NULL,
p_attach_mime IN VARCHAR2 DEFAULT NULL,
p_attach_blob IN BLOB DEFAULT NULL)
is
l_conn utl_smtp.connection;
l_boundary varchar2(32) := sys_guid();
l_counter pls_integer;
l_length pls_integer;
buff_size pls_integer := 57;
l_raw raw(57);
begin
-- Connect
l_conn := utl_smtp.open_connection( <a> );
utl_smtp.helo( l_conn, '<b>' );
utl_smtp.mail( l_conn, p_from );
utl_smtp.rcpt( l_conn, p_to );
utl_smtp.open_data(l_conn);
-- Header
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, 'CC: ' || p_cc || utl_tcp.crlf );
utl_smtp.write_data( l_conn, 'Subject: ' || p_subject || utl_tcp.crlf );
utl_smtp.write_data( l_conn, 'MIME-Version: 1.0' || utl_tcp.crlf );
utl_smtp.write_data( l_conn, 'Content-Type: multipart/mixed; ' || utl_tcp.crlf );
utl_smtp.write_data( l_conn, ' l_boundary= "' || l_boundary || '"' || utl_tcp.crlf );
utl_smtp.write_data( l_conn, utl_tcp.crlf );
-- Body
utl_smtp.write_data( l_conn, '--' || l_boundary || utl_tcp.crlf );
utl_smtp.write_data( l_conn, 'Content-type:text/html;' || utl_tcp.crlf );
utl_smtp.write_data( l_conn, ' charset=iso-8859-1' || utl_tcp.crlf );
utl_smtp.write_data( l_conn, utl_tcp.crlf );
utl_smtp.write_data( l_conn, p_body || utl_tcp.crlf );
utl_smtp.write_data( l_conn, utl_tcp.crlf );
-- Attachment
utl_smtp.write_data ( l_conn, '--' || l_boundary || utl_tcp.crlf );
utl_smtp.write_data ( l_conn, 'Content-Type: '|| p_attach_mime ||';'|| utl_tcp.crlf );
utl_smtp.write_data ( l_conn, 'Content-Disposition: inline; filename="'|| p_attach_name ||'"' || utl_tcp.crlf);
utl_smtp.write_data ( l_conn, 'Content-Transfer-Encoding' || ': ' || 'base64' || utl_tcp.crlf);
utl_smtp.write_data ( l_conn, utl_tcp.crlf);
l_counter := 1;
l_length := dbms_lob.getlength(p_attach_blob);
while l_counter < l_length loop
dbms_lob.read(p_attach_blob, buff_size, l_counter, l_raw);
utl_smtp.write_raw_data( l_conn, utl_encode.base64_encode(l_raw));
utl_smtp.write_data( l_conn, utl_tcp.crlf);
l_counter := l_counter + buff_size;
end loop;
utl_smtp.write_data( l_conn, utl_tcp.crlf);
-- Close Email
utl_smtp.write_data( l_conn, '--' || l_boundary || '--' || utl_tcp.crlf );
utl_smtp.write_data( l_conn, utl_tcp.crlf || '.' || utl_tcp.crlf );
utl_smtp.close_data( l_conn );
utl_smtp.quit( l_conn );
end;

How to use Oracle's UTL_SMTP to send a message body that included an embedded image

I'm attempting to use Oracle's 11.g's UTL_SMTP to send a message body that includes an embedded image. I have this process working for a standard text body, and for an eMail that may contain attachments (Word doc, JPG image, etc.). I'm stuck on making this work with an image embedded in the body of the eMail. When I include and embedded image, the eMail displays in Outlook 2013 as a red X where the image should be. The rest of the text appears fine. The html body of the eMail is passed in to the procedure via "p_html".
My Procedure looks like this:
create or replace procedure html_email_attachments(
p_to in varchar2,
p_from in varchar2,
p_subject in varchar2,
p_text in varchar2 default null,
p_html in varchar2 default null,
p_smtp_hostname in varchar2,
p_smtp_portnum in varchar2,
p_smtp_username in varchar2,
p_smtp_password in varchar2,
p_event_pkey in number
)
is
l_boundary varchar2(255) default 'a1b2c3d4e3f2g1';
l_connection utl_smtp.connection;
l_body_html clob := empty_clob; --This LOB will be the email message
l_offset number;
l_ammount number;
l_temp varchar2(32767) default null;
l_encoded_username varchar2(2048);
l_encoded_password varchar2(2048);
l_attach_mime varchar2(1024);
l_attach_name varchar2(1024);
l_attach_blob blob;
l_attachment_pkeys DBMS_SQL.varchar2_table;
l_step PLS_INTEGER := 12000; -- A multiple of 3 and <= 24573
crlf varchar2(2) := CHR(13) || CHR(10);
diag varchar2(4000);
v_raw raw(57);
v_length integer := 0;
v_buffer_size integer := 57;
v_offset integer := 1;
begin
-- Store all the attachment primary keys into l_attachment_pkeys
Select ma.prim_key Bulk Collect Into l_attachment_pkeys
From mail_attachment ma
Where ma.event_fkey = p_event_pkey;
-- Encode p_smtp_username and p_smtp_password
l_encoded_username := UTL_RAW.cast_to_varchar2
(UTL_ENCODE.base64_encode(UTL_RAW.cast_to_raw(p_smtp_username)));
l_encoded_password := UTL_RAW.cast_to_varchar2
(UTL_ENCODE.base64_encode(UTL_RAW.cast_to_raw(p_smtp_password)));
-- set the l_connection variable
l_connection := UTL_SMTP.open_connection(p_smtp_hostname, p_smtp_portnum);
-- begin the connection
utl_smtp.ehlo(l_connection, p_smtp_hostname);--DO NOT USE HELO
-- authenticate to the server using the encoded username and password
utl_smtp.command(l_connection, 'AUTH', 'LOGIN');
utl_smtp.command(l_connection, l_encoded_username);
utl_smtp.command(l_connection, l_encoded_password);
-- First, establish the mail's From and To. This is essential
utl_smtp.mail( l_connection, p_from );
utl_smtp.rcpt( l_connection, p_to );
-- Define the Header
l_temp := l_temp || 'MIME-Version: 1.0' || crlf;
l_temp := l_temp || 'To: ' || p_to || crlf;
l_temp := l_temp || 'From: ' || p_from || crlf;
l_temp := l_temp || 'Subject: ' || p_subject || crlf;
l_temp := l_temp || 'Reply-To: ' || p_from || crlf;
l_temp := l_temp || 'Content-Type: multipart/mixed; boundary=' ||
chr(34) || l_boundary || chr(34) || crlf;
----------------------------------------------------
-- Write the headers
dbms_lob.createtemporary( l_body_html, false, 10 );
dbms_lob.write(l_body_html,length(l_temp),1,l_temp);
----------------------------------------------------
-- Write the HTML boundary
-- Identify the content type as text/html
-- Determine the offset (initially it's 1)
-- Write out
l_temp := crlf || crlf ||'--' || l_boundary || crlf;
l_temp := l_temp || 'content-type: text/html;' || crlf || crlf;
l_offset := dbms_lob.getlength(l_body_html) + 1;
dbms_lob.write(l_body_html,length(l_temp),l_offset,l_temp);
----------------------------------------------------
-- Write the HTML portion of the message
l_offset := dbms_lob.getlength(l_body_html) + 1;
dbms_lob.write(l_body_html,length(p_html),l_offset,p_html);
----------------------------------------------------
-- Send the email body in 1900 byte chunks to UTL_SMTP
l_offset := 1;
l_ammount := 1900;
utl_smtp.open_data(l_connection);
while l_offset < dbms_lob.getlength(l_body_html) loop
utl_smtp.write_data(l_connection,
dbms_lob.substr(l_body_html,l_ammount,l_offset));
l_offset := l_offset + l_ammount ;
l_ammount := least(1900,dbms_lob.getlength(l_body_html) - l_ammount);
end loop;
--The following crlf is necessary after the body is written
utl_smtp.write_data(l_connection, crlf);
----------------------------------------------------
-- Write the attachments of the message
-- Loop through all the selected primary keys in l_attachment_pkeys
While l_attachment_pkeys is null
Loop
For i IN l_attachment_pkeys.FIRST .. l_attachment_pkeys.LAST
Loop
-- Determine the attachment variables for each instance of attachments
Select mime_type into l_attach_mime
from mail_attachment where prim_key = l_attachment_pkeys(i);
Select file_name into l_attach_name
from mail_attachment where prim_key = l_attachment_pkeys(i);
Select attachment into l_attach_blob
from mail_attachment where prim_key = l_attachment_pkeys(i);
v_length := dbms_lob.getlength(l_attach_blob);
-- Write out the boundary
UTL_SMTP.write_data(l_connection, '--' || l_boundary || crlf);
-- Write out the attachment metadata
UTL_SMTP.write_data(l_connection, 'Content-Type: ' || l_attach_mime ||
'; name=' || chr(34) || l_attach_name || chr(34) || crlf);
UTL_SMTP.write_data(l_connection, 'Content-Transfer-Encoding: base64' ||
crlf);
UTL_SMTP.write_data(l_connection, 'Content-Disposition: attachment;
filename="' || l_attach_name || '"' || crlf || crlf);
--Write out the attachment blob in portions of l_step length
FOR k IN 0 .. TRUNC((DBMS_LOB.getlength(l_attach_blob) - 1 )/l_step)
LOOP
UTL_SMTP.write_data(l_connection, UTL_RAW.cast_to_varchar2
(UTL_ENCODE.base64_encode(DBMS_LOB.substr(l_attach_blob,
l_step, k * l_step + 1))));
END LOOP;
UTL_SMTP.write_data(l_connection, crlf);
End Loop;
End Loop;
----------------------------------------------------
-- Write the final html boundary
utl_smtp.write_data(l_connection,
crlf || '--' || l_boundary || '--' || crlf);
----------------------------------------------------
-- Close the connection and end
utl_smtp.close_data(l_connection);
utl_smtp.quit( l_connection );
dbms_lob.freetemporary(l_body_html);
end;
A sample "p_html" field looks like this:
<p>
Text right before the image.</p>
<p>
<img alt="HarryPotter" src="data:image/jpeg;base64,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" /></p>
<p>
Text right after the image.</p>
the following code works for me:
DECLARE
conn utl_smtp.connection;
BOUNDARY VARCHAR2 (256) := '-----090303020209010600070908';
i pls_integer;
len pls_integer;
buff_size pls_integer := 57;
l_raw raw(57);
p_image blob;
MailServer VARCHAR2(50) := 'xxxxxx.xxxxx.xxxxxxx.xxxxx';
l_message VARCHAR2(32767) :='<html>
<body>
<img src="cid:banner" alt="banner"/>
<br>
Test HTML with Embedded Image-chk latest
<p>And here it is:</p>
<p>The end.</p>
</body>
</html>
';
begin
SELECT PIC
INTO p_image
FROM TEMP_MAIL_PIC_BLOB
WHERE PIC_ID = 1;
conn := utl_smtp.open_connection(MailServer, 25);
UTL_SMTP.helo (conn, MailServer);
UTL_SMTP.mail (conn, 'from#abc.com');
UTL_SMTP.rcpt (conn, 'to#abc.com');
UTL_SMTP.open_data (conn);
UTL_SMTP.write_data (conn, 'From' || ': ' || 'from#test.com'|| UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, 'To' || ': ' || 'to#test.com'|| UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, 'MIME-Version: 1.0' || UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, 'Subject: image inline testing' || UTL_TCP.CRLF) ;
UTL_SMTP.write_data (conn, 'Content-Type: multipart/mixed; boundary="' || BOUNDARY || '"' || UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, '--' || BOUNDARY || UTL_TCP.CRLF );
UTL_SMTP.write_data (conn, 'Content-Type: text/html; charset=US-ASCII'|| UTL_TCP.CRLF );
UTL_SMTP.write_data (conn, UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, l_message);
UTL_SMTP.write_data (conn, UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, '--' || BOUNDARY || UTL_TCP.CRLF );
UTL_SMTP.write_data (conn, 'Content-Type: image/jpg;'|| UTL_TCP.CRLF );
UTL_SMTP.write_data (conn, 'Content-Disposition: inline; filename="banner.jpg"' || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA (conn, 'Content-ID: <banner> ' || UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, 'Content-Transfer-Encoding' || ': ' || 'base64' || UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, UTL_TCP.CRLF);
i := 1;
len := dbms_lob.getlength(p_image);
while i < len
loop
dbms_lob.read(p_image, buff_size, i, l_raw);
utl_smtp.write_raw_data(conn, utl_encode.base64_encode(l_raw));
utl_smtp.write_data(conn, utl_tcp.crlf);
i := i + buff_size;
end loop;
utl_smtp.write_data(conn, utl_tcp.crlf);
UTL_SMTP.write_data (conn, '--' || BOUNDARY || '--' || UTL_TCP.CRLF);
UTL_SMTP.write_data (conn, UTL_TCP.CRLF);
UTL_SMTP.close_data (conn);
UTL_SMTP.quit (conn);
end;
Regards
Giova

body of the mail getting printed inside attachment file while sending mail through PL/SQL

My Requirement is to send data coming from oracle tables as an excel sheet attachment through mail to the customers. I am able to get the attachment but whatever I write as the body of mail, it goes inside the excel sheet.
Code:
CREATE OR REPLACE PROCEDURE trackekr(cursor1 IN OUT SYS_REFCURSOR)
AS
v_connection UTL_SMTP.connection;
v_smtp VARCHAR2(255):='mail.bbc.com';
v_clob CLOB := EMPTY_CLOB();
v_len INTEGER;
v_index INTEGER;
c_mime_boundary CONSTANT VARCHAR2(256) := 'the boundary can be almost anything';
headerLines CLOB := EMPTY_CLOB();
BEGIN
OPEN cursor1 FOR
SELECT COUNTRY_ID, START_DATE
FROM Table WHERE OBJECT_NAME = 'XYZ';
DBMS_LOB.CreateTemporary( v_clob, true );
headerLines := 'COUNTRY_ID,START_DATE'|| UTL_TCP.crlf; --// create CSV header line
DBMS_LOB.WriteAppend( v_clob, length(headerLines), headerLines ); --// write it to CLOB
--// start loop to add data lines to CSV
FOR cursor1 in
( SELECT COUNTRY_ID, START_DATE
FROM Table WHERE OBJECT_NAME = 'XYZ')
LOOP
v_clob :=
v_clob
|| cursor1.COUNTRY_ID
|| ','
|| cursor1.START_DATE
|| UTL_TCP.crlf;
END LOOP;
-- UTL
v_connection := UTL_SMTP.open_connection(v_smtp, 25);
UTL_SMTP.helo(v_connection, v_smtp);
UTL_SMTP.mail(v_connection, 'abc.singh#yahoo.in');
UTL_SMTP.rcpt(v_connection, 'abc.singh#wbc.com');
UTL_SMTP.open_data(v_connection);
UTL_SMTP.write_data(v_connection, 'From: ' || 'abc.singh#yahoo.in' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, 'To: ' || 'abc.singh#wbc.com' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, 'Subject: test subject' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, 'MIME-Version: 1.0' || UTL_TCP.crlf);
UTL_SMTP.write_data(
v_connection,
'Content-Type: multipart/mixed; boundary="' || c_mime_boundary || '"' || UTL_TCP.crlf
);
UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
UTL_SMTP.write_data(
v_connection,
'This is a multi-part message in MIME format.' || UTL_TCP.crlf
);
UTL_SMTP.write_data(v_connection, '--' || c_mime_boundary || UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, 'Content-Type: text/plain' || UTL_TCP.crlf);
-- Set up attachment header
UTL_SMTP.write_data(
v_connection,
'Content-Disposition: attachment; filename="' || 'FIRSTFILE.csv' || '"' || UTL_TCP.crlf
);
UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
-- Write attachment contents
v_len := DBMS_LOB.getlength(v_clob);
v_index := 1;
WHILE v_index <= v_len
LOOP
UTL_SMTP.write_data(v_connection, DBMS_LOB.SUBSTR(v_clob, 32000, v_index));
v_index := v_index + 32000;
END LOOP;
-- End attachment
UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, '--' || c_mime_boundary || '--' || UTL_TCP.crlf);
if DBMS_LOB.IsOpen( v_clob ) = 1 then
DBMS_LOB.FreeTemporary( v_clob );
end if;
UTL_SMTP.close_data(v_connection);
UTL_SMTP.quit(v_connection);
END;
In a multi-part MIME message, body is a "part" by itself and needs it's own boundary.
In your original code, you find these lines:
UTL_SMTP.write_data(
v_connection,
'This is a multi-part message in MIME format.' || UTL_TCP.crlf
);
Just after those lines, you add this bit of code:
-- Body >>>
UTL_SMTP.write_data(v_connection, '--' || c_mime_boundary || UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, 'Content-Type: text/plain' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, 'Hello, this is the body.'||UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
-- <<< Body
Don't remove anything from your original code.
That way the body is within it's own boundary part, just like the csv file, but without a Content-Disposition: attachment header.

PL/SQL send email with attachment?

we have a table with files saved as BLOB
I write a code that email these files as an attachment!
everything works fine so far, but the files (EXCEL,PDF, ... what ever) are not readable by the programs, only text files and excel will open but after some error message, where PDFs all not be opened at all!
here is the part of the code in question!
utl_smtp.write_data( l_connection, '--'|| l_boundary || utl_tcp.crlf);
utl_smtp.write_data( l_connection, 'Content-Type: application/octet-stream' || utl_tcp.crlf);
utl_smtp.write_data( l_connection, 'Content-Disposition: attachment; filename="' || V_NAME || '"' || utl_tcp.crlf);
utl_smtp.write_data( l_connection, 'Content-Transfer-Encoding: base64' || utl_tcp.crlf );
utl_smtp.write_data( l_connection, utl_tcp.crlf );
v_length := dbms_lob.getlength(V_BLOB_CONTENT);
while v_offset < v_length loop
dbms_lob.read( V(i).BLOB_CONTENT, v_buffer_size, v_offset, v_raw );
utl_smtp.write_raw_data( l_connection, utl_encode.base64_encode(v_raw) );
utl_smtp.write_data( l_connection, utl_tcp.crlf );
v_offset := v_offset + v_buffer_size;
end loop while_loop;
utl_smtp.write_data( l_connection, utl_tcp.crlf );
any suggestions?
here is a procedure that I use to do just that
PROCEDURE StreamAttachmentToConn( p_conn IN OUT utl_smtp.connection
,p_boundary IN raw
,p_FileName IN VARCHAR2
,p_FileData IN BLOB) PARALLEL_ENABLE
AS
l_len integer := 0 ;
l_idx integer := 1 ;
l_buff_size integer := 57 ;
l_raw raw(57) ;
BEGIN
-- Attachment
utl_smtp.write_data( p_conn, '--' || p_boundary || utl_tcp.crlf );
utl_smtp.write_data( p_conn, 'Content-Type: application/octet-stream' || utl_tcp.crlf );
utl_smtp.write_data( p_conn, 'Content-Disposition: attachment; ' || utl_tcp.crlf );
utl_smtp.write_data( p_conn, ' filename="' || p_FileName || '"' || utl_tcp.crlf );
utl_smtp.write_data( p_conn, 'Content-Transfer-Encoding: base64' || utl_tcp.crlf );
utl_smtp.write_data( p_conn, utl_tcp.crlf );
-- Loop through the blob
-- chuck it up into 57-byte pieces
-- and base64 encode it and write it into the mail buffer
l_len := dbms_lob.getlength(p_FileData);
-- force reinit on this may change
l_buff_size := 57 ;
l_idx := 1;
while l_idx < l_len loop
dbms_lob.read( p_FileData , l_buff_size, l_idx, l_raw );
utl_smtp.write_raw_data( p_conn, utl_encode.base64_encode(l_raw) );
utl_smtp.write_data( p_conn, utl_tcp.crlf );
l_idx := l_idx + l_buff_size;
end loop;
END StreamAttachmentToConn;
I use this to add multiple attachments to a single email. works like a champ for me.
one thing, the p_boundary is passed in as
l_boundary raw(32) := sys_guid();
I see that you already have an l_boundary and that is what you should use.
this is based on http://christopherbeck.wordpress.com/category/plsql/ as well as http://www.oracle-base.com/articles/misc/EmailFromOraclePLSQL.php#attachment
.
then in your code, just pass in your smtp connection, the l_boundary (ie RAW sys_guid or whatever you are using, the name of the file (as it will appear on the email attachment), and the BLOB.
*EDIT --> additional information *
Ours are the same with the assumption of:
--> assume v_offset starts with 1
--> v_buffer_size assume 57
But I have noticed that there is an order that you must follow to get it to work (notably, put the attachments next to the END after body!!!
Connect LOGIC
add all of the recipients
Header LOGIC :"FROM", Subject
Body logic (body text etc)
Attachments
then after the attachments close the email (this is specifically what I have after my attachments:
utl_smtp.write_data( l_conn, utl_tcp.crlf );
-- Close Email
utl_smtp.write_data( l_conn, '--' || l_boundary || '--' || utl_tcp.crlf );
utl_smtp.write_data( l_conn, utl_tcp.crlf || '.' || utl_tcp.crlf );
utl_smtp.close_data( l_conn );
utl_smtp.quit( l_conn );
Tim Hall has a great site (oracle-base) that has what you're looking for. Note in particular how the encoding is done.
I've used similar code to send emails via pl/sql without problem

Resources