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.
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);
....
...
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;
I normally use utl_smtp to send emails in pl/sql, but recently I've had to send a pdf file as attachment and utl_smtp does not allow it. Can you help me on how to send one in pl/sql?
An attachment it's just base64 encoded text in the body of the message separated from the rest of the text with a boundary section. So if you can send text, you can also send attachments of any type.
Here you have a procedure for sending an email with an attachment.
CREATE OR REPLACE PROCEDURE send_mail (p_to IN VARCHAR2,
p_from IN VARCHAR2,
p_subject IN VARCHAR2,
p_text_msg IN VARCHAR2 DEFAULT NULL,
p_attach_name IN VARCHAR2 DEFAULT NULL,
p_attach_mime IN VARCHAR2 DEFAULT NULL,
p_attach_blob IN BLOB DEFAULT NULL,
p_smtp_host IN VARCHAR2,
p_smtp_port IN NUMBER DEFAULT 25)
AS
l_mail_conn UTL_SMTP.connection;
l_boundary VARCHAR2(50) := '----=*#abc1234321cba#*=';
l_step PLS_INTEGER := 12000; -- make sure you set a multiple of 3 not higher than 24573
BEGIN
l_mail_conn := UTL_SMTP.open_connection(p_smtp_host, p_smtp_port);
UTL_SMTP.helo(l_mail_conn, p_smtp_host);
UTL_SMTP.mail(l_mail_conn, p_from);
UTL_SMTP.rcpt(l_mail_conn, p_to);
UTL_SMTP.open_data(l_mail_conn);
UTL_SMTP.write_data(l_mail_conn, 'Date: ' || TO_CHAR(SYSDATE, 'DD-MON-YYYY HH24:MI:SS') || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'To: ' || p_to || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'From: ' || p_from || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'Subject: ' || p_subject || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'Reply-To: ' || p_from || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'MIME-Version: 1.0' || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'Content-Type: multipart/mixed; boundary="' || l_boundary || '"' || UTL_TCP.crlf || UTL_TCP.crlf);
IF p_text_msg IS NOT NULL THEN
UTL_SMTP.write_data(l_mail_conn, '--' || l_boundary || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'Content-Type: text/plain; charset="iso-8859-1"' || UTL_TCP.crlf || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, p_text_msg);
UTL_SMTP.write_data(l_mail_conn, UTL_TCP.crlf || UTL_TCP.crlf);
END IF;
IF p_attach_name IS NOT NULL THEN
UTL_SMTP.write_data(l_mail_conn, '--' || l_boundary || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'Content-Type: ' || p_attach_mime || '; name="' || p_attach_name || '"' || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'Content-Transfer-Encoding: base64' || UTL_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, 'Content-Disposition: attachment; filename="' || p_attach_name || '"' || UTL_TCP.crlf || UTL_TCP.crlf);
FOR i IN 0 .. TRUNC((DBMS_LOB.getlength(p_attach_blob) - 1 )/l_step) LOOP
UTL_SMTP.write_data(l_mail_conn, UTL_RAW.cast_to_varchar2(UTL_ENCODE.base64_encode(DBMS_LOB.substr(p_attach_blob, l_step, i * l_step + 1))));
END LOOP;
UTL_SMTP.write_data(l_mail_conn, UTL_TCP.crlf || UTL_TCP.crlf);
END IF;
UTL_SMTP.write_data(l_mail_conn, '--' || l_boundary || '--' || UTL_TCP.crlf);
UTL_SMTP.close_data(l_mail_conn);
UTL_SMTP.quit(l_mail_conn);
END;
/
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.