Send a PDF file to telegram using PL/SQL- UTL_HTTP code - oracle

I'm trying to send a pdf document and a small description about it from my server to a Telegram group using a Telegram bot user. I'm able to send a document by itself using the method /sendDocument. However, that is not exactly what I want. I wonder is that even possible to do ?
The actual output message is "ORA-29263: HTTP protocol error."
declare
l_attachment blob;
l_newline varchar2(50) := chr(13) || chr(10);
lco_boundary constant varchar2(30) := '----=*#abc1234321cba#*=';
l_http_request utl_http.req;
l_request_body clob;
l_request_body_length number;
l_http_response utl_http.resp;
l_response_header_name varchar2(256);
l_response_header_value varchar2(1024);
l_response_body varchar2(32767);
l_offset number := 1;
l_amount number := 2000;
l_buffer varchar2(2000);
postData clob;
p_id varchar2(50) := '********';
begin
select invoce into l_attachment from some_table;
l_request_body := l_newline
|| '--' || lco_boundary || l_newline
|| 'Content-Disposition: form-data; name="document"; filename="file.pdf"' || l_newline
|| 'Content-Type: application/pdf' || l_newline
|| l_newline
|| apex_web_service.blob2clobbase64(l_attachment) || l_newline
|| '--' || lco_boundary || l_newline
|| 'Content-Disposition: form-data; name="document"' || l_newline
|| l_newline
|| 'file.pdf' || l_newline
|| '--' || lco_boundary || l_newline
|| 'Content-Disposition: form-data; name="MAX_FILE_SIZE"' || l_newline
|| l_newline
|| '4000000' || l_newline
|| '--' || lco_boundary || '--';
dbms_output.put_line('Request body>');
dbms_output.put_line(dbms_lob.substr(l_request_body, 4000, 1));
l_request_body_length := dbms_lob.getlength(l_request_body);
utl_http.set_wallet('file:/u02/oracle/upload/WALLET_TELEGRAM/', '******');
l_http_request := utl_http.begin_request(
url => 'https://api.telegram.org/bot<MY_KEY>/sendDocument',
method => 'POST',
http_version => 'HTTP/1.1'
);
postData := postData || 'chat_id=' || p_id || '&';
postData := postData || 'document=';
utl_http.set_header(l_http_request, 'Content-Type', 'multipart/form-data; boundary="' || lco_boundary || '"');
utl_http.set_header(l_http_request, 'Content-Length', l_request_body_length);
utl_http.write_text(l_http_request, postData);
while l_offset < l_request_body_length loop
dbms_lob.read(l_request_body, l_amount, l_offset, l_buffer);
utl_http.write_text(l_http_request, l_buffer);
l_offset := l_offset + l_amount;
end loop;
l_http_response := utl_http.get_response(l_http_request);
for i in 1 .. utl_http.get_header_count(l_http_response) loop
utl_http.get_header(l_http_response, i, l_response_header_name, l_response_header_value);
l_response_header_value);
end loop;
utl_http.read_text(l_http_response, l_response_body, 32767);
dbms_output.put_line(l_response_body);
if l_http_request.private_hndl is not null then
utl_http.end_request(l_http_request);
end if;
if l_http_response.private_hndl is not null then
utl_http.end_response(l_http_response);
end if;
exception
when others then
if l_http_request.private_hndl is not null then
utl_http.end_request(l_http_request);
end if;
if l_http_response.private_hndl is not null then
utl_http.end_response(l_http_response);
end if;
raise;
end;

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.

Unable to send mail with an attachment through Oracle using UTL_SMTP

I am trying to send a mail with an attachment through oracle. But I am getting
Oracle error - ORA-29279: SMTP permanent error: 554 Transaction failed: Expected ';', got "/"message
in my code at below mentioned step.
L_STEP := 32;
UTL_SMTP.CLOSE_DATA(L_CONNECTION);
I am not able to understand where I am making a mistake.
Calling procedure like -
USP_SEND_MAIL(P_TO => 'rahul.more#XYZ.com',
P_CC => 'vishal.patil#XYZ.com',
P_BCC => NULL,
P_FROM =>'abc#xyz.com',
P_SUBJECT => 'Test mail',
P_FILENAME1 => 'Test_File-27 APR 2022 - 12 PM.xls',
P_HTML => '<BR> Dear Sir/Madam <BR>
<BR> Please find attached file.<BR>
<BR> Total count-66<BR>
<BR>Regards <BR> System generated Mailer',
P_ERR_FLAG => L_ERR_FLAG);
Below is my code
PROCEDURE USP_SEND_MAIL (P_TO IN VARCHAR2,
P_CC IN VARCHAR2,
P_BCC IN VARCHAR2,
P_FROM IN VARCHAR2,
P_SUBJECT IN VARCHAR2,
P_FILENAME1 VARCHAR2,
P_HTML LONG,
P_ERR_FLAG OUT NUMBER) IS
L_CONNECTION UTL_SMTP.CONNECTION;
P_SMTP_HOSTNAME VARCHAR2(100);
P_SMTP_PORTNUM VARCHAR2(100);
L_STEP INTEGER := 0;
L_TO VARCHAR2(4000);
L_CC VARCHAR2(4000);
L_BCC VARCHAR2(4000);
CURSOR C1 IS
SELECT 0,
'CERTIFICATE' EBIZ_DATA
FROM DUAL
UNION ALL
SELECT *
FROM (SELECT 1, t.CERT_NO
FROM CERTIFICATE t
ORDER BY 1)
ORDER BY 1;
BEGIN
L_STEP := 1;
-----***** STAGING MAILER CONFIG ****--------
P_SMTP_HOSTNAME := 'email-*********.amazonaws.com';
P_SMTP_PORTNUM := '000';
L_CONNECTION := UTL_SMTP.open_connection(P_SMTP_HOSTNAME,
P_SMTP_PORTNUM,
wallet_path => '*****/oracle19c/owm/wallets',
wallet_password => '********',
secure_connection_before_smtp => FALSE);
L_STEP := 2;
-----***** STAGING MAILER CONFIG ****--------
utl_smtp.helo(L_CONNECTION, P_SMTP_HOSTNAME);
--utl_smtp.command(L_CONNECTION, 'STARTTLS');
utl_smtp.starttls(L_CONNECTION);
utl_smtp.command(L_CONNECTION, 'AUTH LOGIN');
utl_smtp.command(L_CONNECTION,
utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw('********'))));
utl_smtp.command(L_CONNECTION,
utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw('********'))));
L_STEP := 3;
UTL_SMTP.HELO(L_CONNECTION, P_SMTP_HOSTNAME);
UTL_SMTP.MAIL(L_CONNECTION, P_FROM);
FOR x IN (SELECT LEVEL AS id,
REGEXP_SUBSTR(P_TO, '[^;]+', 1, LEVEL) AS TO_EMAIL_NAME
FROM DUAL
CONNECT BY REGEXP_SUBSTR(P_TO, '[^;]+', 1, LEVEL) IS NOT NULL) LOOP
utl_smtp.Rcpt(L_CONNECTION, x.TO_EMAIL_NAME);
END LOOP;
IF P_CC IS NOT NULL THEN
FOR x IN (SELECT LEVEL AS id,
REGEXP_SUBSTR(P_CC, '[^;]+', 1, LEVEL) AS CC_EMAIL_NAME
FROM DUAL
CONNECT BY REGEXP_SUBSTR(P_CC, '[^;]+', 1, LEVEL) IS NOT NULL) LOOP
utl_smtp.Rcpt(L_CONNECTION, x.CC_EMAIL_NAME);
L_CC := L_CC || 'CC: ' || x.CC_EMAIL_NAME || CRLF;
END LOOP;
ELSE
L_CC := '';
END IF;
IF P_BCC IS NOT NULL THEN
FOR x IN (SELECT LEVEL AS id,
REGEXP_SUBSTR(P_BCC, '[^;]+', 1, LEVEL) AS BCC_EMAIL_NAME
FROM DUAL
CONNECT BY REGEXP_SUBSTR(P_BCC, '[^;]+', 1, LEVEL) IS NOT NULL) LOOP
utl_smtp.Rcpt(L_CONNECTION, x.BCC_EMAIL_NAME);
L_BCC := L_BCC || 'BCC: ' || x.BCC_EMAIL_NAME || CRLF;
END LOOP;
ELSE
L_BCC := '';
END IF;
L_STEP := 8;
UTL_SMTP.OPEN_DATA(L_CONNECTION);
L_STEP := 9;
-- Use MIME mail header
UTL_SMTP.WRITE_DATA(L_CONNECTION, 'MIME-Version: 1.0' || UTL_TCP.crlf);
L_STEP := 10;
UTL_SMTP.WRITE_DATA(L_CONNECTION,
'Date: ' ||
TO_CHAR(SYSDATE, 'Dy, DD Mon YYYY hh24:mi:ss') || UTL_TCP.crlf);
L_STEP := 11;
UTL_SMTP.WRITE_DATA(L_CONNECTION, 'TO: ' || P_TO || UTL_TCP.crlf);
IF L_CC IS NOT NULL THEN
L_STEP := 12;
--UTL_SMTP.WRITE_DATA(L_CONNECTION, 'Cc: ' || P_CC || UTL_TCP.crlf);
UTL_SMTP.WRITE_DATA(L_CONNECTION, L_CC);
END IF;
IF L_BCC IS NOT NULL THEN
L_STEP := 13;
--UTL_SMTP.WRITE_DATA(L_CONNECTION, 'Bcc: ' || P_BCC || UTL_TCP.crlf);
UTL_SMTP.WRITE_DATA(L_CONNECTION, L_BCC);
END IF;
L_STEP := 14;
UTL_SMTP.WRITE_DATA(L_CONNECTION, 'From: ' || P_FROM || UTL_TCP.crlf);
L_STEP := 15;
UTL_SMTP.WRITE_DATA(L_CONNECTION, 'Subject: ' || P_SUBJECT || UTL_TCP.crlf);
L_STEP := 16;
UTL_SMTP.WRITE_DATA(L_CONNECTION, 'Reply-To: ' || P_FROM || UTL_TCP.crlf);
L_STEP := 17;
UTL_SMTP.WRITE_DATA(L_CONNECTION,
'Content-Type: multipart/mixed; boundary="EBIZ_BOUNDARY"' || UTL_TCP.crlf || UTL_TCP.crlf);
L_STEP := 18;
UTL_SMTP.WRITE_DATA(L_CONNECTION, 'This is multipart message' || UTL_TCP.crlf);
L_STEP := 19;
UTL_SMTP.WRITE_DATA(L_CONNECTION, '--EBIZ_BOUNDARY' || UTL_TCP.crlf);
L_STEP := 20;
-- Message body
UTL_SMTP.WRITE_DATA(L_CONNECTION, 'Content-Type: text/html;' || UTL_TCP.crlf);
L_STEP := 21;
UTL_SMTP.WRITE_DATA(L_CONNECTION, 'Content-Transfer_Encoding: 7bit' || UTL_TCP.crlf || UTL_TCP.crlf);
L_STEP := 22;
UTL_SMTP.WRITE_DATA(L_CONNECTION, P_HTML || UTL_TCP.crlf);
L_STEP := 23;
UTL_SMTP.WRITE_DATA(L_CONNECTION, ' ' || UTL_TCP.crlf || UTL_TCP.crlf || UTL_TCP.crlf || UTL_TCP.crlf || UTL_TCP.crlf);
L_STEP := 24;
-- Attachment section 1
UTL_SMTP.WRITE_DATA(L_CONNECTION, '--EBIZ_BOUNDARY' || UTL_TCP.CRLF);
L_STEP := 25;
--UTL_SMTP.WRITE_DATA(L_CONNECTION, 'CONTENT-TYPE: TEXT/PLAIN;' || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(L_CONNECTION,
'CONTENT-TYPE: APPLICATION/APPLICATION/VND.OPENXMLFORMATS-OFFICEDOCUMENT.SPREADSHEETML.SHEET;' || UTL_TCP.CRLF);
L_STEP := 26;
UTL_SMTP.WRITE_DATA(L_CONNECTION,
' NAME="' || P_FILENAME1 || '"' || UTL_TCP.CRLF);
L_STEP := 27;
UTL_SMTP.WRITE_DATA(L_CONNECTION,
'CONTENT-TRANSFER_ENCODING: 8BIT' || UTL_TCP.CRLF);
L_STEP := 28;
UTL_SMTP.WRITE_DATA(L_CONNECTION,
'CONTENT-DISPOSITION: ATTACHMENT;' || UTL_TCP.CRLF);
L_STEP := 29;
UTL_SMTP.WRITE_DATA(L_CONNECTION,
' FILENAME="' || P_FILENAME1 || '"' || UTL_TCP.CRLF || UTL_TCP.CRLF);
L_STEP := 30;
FOR X IN C1 LOOP
UTL_SMTP.WRITE_DATA(L_CONNECTION, X.EBIZ_DATA || UTL_TCP.CRLF);
END LOOP;
-- End MIME mail
L_STEP := 31;
UTL_SMTP.WRITE_DATA(L_CONNECTION, UTL_TCP.crlf || UTL_TCP.crlf || '--EBIZ_BOUNDARY--');
L_STEP := 32; **GETTING AN ERROR HERE**
UTL_SMTP.CLOSE_DATA(L_CONNECTION);
L_STEP := 33;
UTL_SMTP.QUIT(L_CONNECTION);
P_ERR_FLAG := 0;
EXCEPTION
WHEN UTL_SMTP.INVALID_OPERATION THEN
P_ERR_FLAG := 1;
IL_ERROR_LOGGING.ERROR(MESSAGE => SQLERRM || 'message',
MODULE => 'RETAIL UNSYNC POLICY MAILER',
V_PARAMATER => (PARAMS(' L_STEP =>' || L_STEP)));
UTL_SMTP.QUIT(L_CONNECTION);
WHEN UTL_SMTP.TRANSIENT_ERROR THEN
P_ERR_FLAG := 1;
IL_ERROR_LOGGING.ERROR(MESSAGE => SQLERRM || 'message',
MODULE => 'RETAIL UNSYNC POLICY MAILER',
V_PARAMATER => (PARAMS(' L_STEP =>' || L_STEP)));
UTL_SMTP.QUIT(L_CONNECTION);
WHEN UTL_SMTP.PERMANENT_ERROR THEN
P_ERR_FLAG := 1;
IL_ERROR_LOGGING.ERROR(MESSAGE => SQLERRM || 'message',
MODULE => 'RETAIL UNSYNC POLICY MAILER',
V_PARAMATER => (PARAMS(' L_STEP =>' || L_STEP)));
UTL_SMTP.QUIT(L_CONNECTION);
WHEN OTHERS THEN
P_ERR_FLAG := 99;
IL_ERROR_LOGGING.ERROR(MESSAGE => SQLERRM || 'message',
MODULE => 'RETAIL UNSYNC POLICY MAILER',
V_PARAMATER => (PARAMS(' L_STEP =>' || L_STEP)));
UTL_SMTP.QUIT(L_CONNECTION);
END;

Got corrupted file after uploading using form-data in plsql

I would like to do a POST from PL/SQL, using as enctype "Multipart/form-data" in order to upload jpeg blob file which is stored in table. I am able to send .txt file. but when i trying to upload image file i am getting corrupted image file.
I am not away much about plsql, so not in proper mannar.
DECLARE
p_url VARCHAR2(255) := 'http://localhost:8080/uploadFile';
utl_req utl_http.req;
utl_resp utl_http.resp;
req_length BINARY_INTEGER;
response_body VARCHAR2(32767);
p_request_body clob;
l_newline VARCHAR2(50) := chr(13) || chr(10);
lco_boundary CONSTANT VARCHAR2(30) := 'AaB03x';
buffer raw(32767);
amount number(15) := 32767;
offset number(15) := 1;
l_attachment blob;
l_file_name VARCHAR2(255);
l_mime_type VARCHAR2(255);
lang_context integer;
warning varchar2(1000);
blb blob;
tmp_blob blob default EMPTY_BLOB();
dest_offset integer:=1;
src_offset integer:=1;
BEGIN
select BLOB_CONTENT, FILENAME, MIME_TYPE into l_attachment, l_file_name,
l_mime_type from X_FILES where ID=12;
p_request_body := l_newline
|| '--'
|| lco_boundary
|| l_newline
|| 'Content-Disposition: form-data; name="file";
filename="'||l_file_name||'"'
|| l_newline
|| 'Content-Type: '||l_mime_type
|| l_newline
|| 'Content-Transfer-Encoding: binary'
|| l_newline
|| l_newline
|| CLOBFROMBLOB(l_attachment)
|| l_newline
|| '--'
|| lco_boundary
|| '--';
dbms_lob.createtemporary(blb, FALSE);
dest_offset := 1;
src_offset := 1;
lang_context := 0;
dbms_lob.converttoblob( blb, p_request_body, dbms_lob.getlength(p_request_body), dest_offset, src_offset, 0, lang_context, warning );
dbms_lob.append(blb,l_attachment);
req_length := dbms_lob.getlength(blb);
utl_req := utl_http.begin_request(url => p_url,method => 'POST',http_version => 'HTTP/1.1');
utl_http.set_header(utl_req,'User-Agent','Mozilla/4.0');
utl_http.set_header(utl_req,'Content-Type','multipart/mixed; boundary="' || lco_boundary || '"');
dbms_output.put_line(req_length);
IF
req_length <= 32767
THEN
utl_http.set_header(utl_req, 'Content-Length', req_length);
utl_http.write_raw(utl_req, blb);
ELSIF req_length > 32767 THEN
utl_http.set_header(utl_req, 'Transfer-Encoding', 'chunked');
WHILE ( offset < req_length ) LOOP
dbms_lob.read(blb, amount, offset, buffer);
utl_http.write_raw(utl_req, buffer);
offset := offset + amount;
END LOOP;
END IF;
utl_resp := utl_http.get_response(utl_req);
utl_http.read_raw(utl_resp,response_body,32767);
utl_http.end_response(utl_resp);
EXCEPTION
WHEN UTL_HTTP.TOO_MANY_REQUESTS THEN
utl_http.END_RESPONSE(utl_resp);
END;
I want to used miltipart/form-data to upload files.

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

Debugging with Oracle's utl_smtp

A client of mine uses Oracle 9i's utl_smtp to send mails out notifications to managers when their employees have made travel requests and they woul like quite a few changes made to the mailouts done.
We're having a lot of problems getting utl_smtp to talk to any smtp server on our network. We've even tried installing free smtp server on the oracle box but it will not spot the mail server running on port 25. The error code is ORA-29278.
So two questions really.
Does anyone have any experience setting up email using Oracle's utl_smtp utility and have any suggestions as to where we might be going wrong.
Does anyone know if it is possible to get utl_smtp to dump text emails to a directory much as you can do if you're using system.net.mail's specifiedpickupdirectory config setting. This would be by far the preferable option.
Thanks, Dan
Looks like the HELO is the problem. Please can we check with a simple testcase...
set serveroutput on
declare
lConnection UTL_SMTP.CONNECTION;
begin
lConnection := UTL_SMTP.OPEN_CONNECTION(your_smtp_server);
DBMS_OUTPUT.PUT_LINE('Opened ok');
UTL_SMTP.HELO(lConnection, your_client_machine_name);
DBMS_OUTPUT.PUT_LINE('HELO ok');
UTL_SMTP.MAIL(lConnection, your_email_address);
UTL_SMTP.RCPT(lConnection, your_email_address);
DBMS_OUTPUT.PUT_LINE('Addressing ok');
end;
/
Looks like we've resolved this.
To answer the two questions.
Double check that the schema calling utl_smtp has execute permissions on sys.utl_smtp, sys.utl_tcp and sys.dbms_lob. Also check that at no time the message being sent is > 32Kb.
No there is no way to get utl_smtp to dump emails to a directory a la system.net.mail.
Thanks to cagcowboy for the help.
Yes, we can telnet to the server.
-- ****** Object: Stored Procedure TRAVELADMIN_DEV.HTML_EMAIL Script Date: 22/08/2008 12:41:02 ******
CREATE PROCEDURE "HTML_EMAIL" (
p_to in varchar2,
p_cc in varchar2,
p_from in varchar2,
p_subject in varchar2,
p_text in varchar2 default null,
p_html in varchar2 default null
)
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;
p_smtp_hostname varchar2(30):= 'rockies';
p_smtp_portnum varchar2(2) := '25';
begin
l_connection := utl_smtp.open_connection( p_smtp_hostname, p_smtp_portnum );
utl_smtp.helo( l_connection, p_smtp_hostname );
utl_smtp.mail( l_connection, p_from );
utl_smtp.rcpt( l_connection, p_to );
l_temp := l_temp || 'MIME-Version: 1.0' || chr(13) || chr(10);
l_temp := l_temp || 'To: ' || p_to || chr(13) || chr(10);
IF ((p_cc <> NULL) OR (LENGTH(p_cc) > 0)) THEN
l_temp := l_temp || 'Cc: ' || p_cc || chr(13) || chr(10);
utl_smtp.rcpt( l_connection, p_cc );
END IF;
l_temp := l_temp || 'From: ' || p_from || chr(13) || chr(10);
l_temp := l_temp || 'Subject: ' || p_subject || chr(13) || chr(10);
l_temp := l_temp || 'Reply-To: ' || p_from || chr(13) || chr(10);
l_temp := l_temp || 'Content-Type: multipart/alternative; boundary=' ||
chr(34) || l_boundary || chr(34) || chr(13) ||
chr(10);
----------------------------------------------------
-- 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 text boundary
l_offset := dbms_lob.getlength(l_body_html) + 1;
l_temp := '--' || l_boundary || chr(13)||chr(10);
l_temp := l_temp || 'content-type: text/plain; charset=us-ascii' ||
chr(13) || chr(10) || chr(13) || chr(10);
dbms_lob.write(l_body_html,length(l_temp),l_offset,l_temp);
----------------------------------------------------
-- Write the plain text portion of the email
l_offset := dbms_lob.getlength(l_body_html) + 1;
dbms_lob.write(l_body_html,length(p_text),l_offset,p_text);
----------------------------------------------------
-- Write the HTML boundary
l_temp := chr(13)||chr(10)||chr(13)||chr(10)||'--' || l_boundary ||
chr(13) || chr(10);
l_temp := l_temp || 'content-type: text/html;' ||
chr(13) || chr(10) || chr(13) || chr(10);
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);
----------------------------------------------------
-- Write the final html boundary
l_temp := chr(13) || chr(10) || '--' || l_boundary || '--' || chr(13);
l_offset := dbms_lob.getlength(l_body_html) + 1;
dbms_lob.write(l_body_html,length(l_temp),l_offset,l_temp);
----------------------------------------------------
-- Send the email 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;
utl_smtp.close_data(l_connection);
utl_smtp.quit( l_connection );
dbms_lob.freetemporary(l_body_html);
end;
The OPEN_CONNECTION parameter should be the FQDN or IP address of the server you're connecting to.
The HELO parameter should be the FQDN of the machine you're connecting from.
If this doesn't work, do you know which line it errors on?

Resources