Emails sent through Oracle losing dots(.) - oracle

I have an oracle procedure that sends emails and there are some inconsistencies happening with dots(.) in the messages.
The problem is that in this specific case the email body is being built as an HTML and there is a link in the body of the email message and one of the dots is being removed from this link. For instance xxx.xxx.xxx is showing in the email as xxxxxx.xxx. This results in the receiver being unable to access the wanted link.
During my research for solutions to this problem I stumbled on the section 4.5.2 of SMTP standard RFC2821 that says:
When a line of mail text is received by the SMTP server, it checks
the line. If the line is composed of a single period, it is treated
as the end of mail indicator. If the first character is a period and
there are other characters on the line, the first character is
deleted.
But how do I deal with this in order to make the links in the emails work properly?
Below the code of the procedure used to send emails:
CREATE OR REPLACE PROCEDURE SEND_MAIL (p_from in VARCHAR2,
p_to in VARCHAR2,
p_subject in VARCHAR2,
p_message in VARCHAR2)
IS
lv_server VARCHAR2(255) := 'xxx.xxx.xxx.xxx';
lv_port NUMBER(10) := 25;
lv_rcpt VARCHAR2(255) := p_to;
lv_from VARCHAR2(255) := p_from;
lv_subject VARCHAR2(255) := p_subject;
lv_message VARCHAR2(20000) := p_message;
lv_conn UTL_SMTP.CONNECTION;
BEGIN
lv_Conn := UTL_SMTP.Open_Connection(lv_server, lv_port);
UTL_SMTP.Helo(lv_conn, lv_server);
UTL_SMTP.Mail(lv_conn, lv_from);
UTL_SMTP.Rcpt(lv_conn, lv_rcpt);
UTL_SMTP.OPEN_DATA(lv_conn);
UTL_SMTP.WRITE_DATA(lv_conn, 'Subject: =?ISO-8859-1?Q?' ||
UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.QUOTED_PRINTABLE_ENCODE(UTL_RAW.CAST_TO_RAW(lv_subject))) ||
'?=' || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(lv_conn, 'MIME-version: 1.0' || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(lv_conn, 'Content-Type: text/html;charset=iso-8859-1' || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(lv_conn, 'Content-Transfer-Encoding: quoted-printable '|| UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(lv_conn, 'From: ' || lv_from || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(lv_conn, 'To: ' || lv_rcpt || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(lv_conn, UTL_TCP.CRLF);
UTL_SMTP.WRITE_RAW_DATA(lv_conn, UTL_ENCODE.QUOTED_PRINTABLE_ENCODE(UTL_RAW.CAST_TO_RAW(Utl_Tcp.Crlf || lv_message)));
UTL_SMTP.WRITE_DATA(lv_conn, UTL_TCP.CRLF);
UTL_SMTP.CLOSE_DATA(lv_conn);
UTL_SMTP.QUIT(lv_conn);
END;

Related

How to send multiple people the mail using UTL_SMTP

I have been trying so hard but not able to implement
Any solution is great appreciated !!!
I am using APEX 20.x
I Built one form which as following content in it : textfiled , textarea , choosfile , button
FROM EMAIL : TextFiled1
SUBJECT : TextFiled2
NOTES : TextArea1
ATTACHMENT : choosefile1
SUBMIT
Database records in table : EMPLOYEE
ID,NAME,AGE,EMAIL,STATUS
11,ALICE,12,abc#protonmail.com,Y
32,BOB,32,acd#protonmail.com,N
45,RAY,22,xyz#protonmail.com,Y
36,TIN,24,tin#protonmail.com,Y
My code :
CREATE OR REPLACE PROCEDURE send_mail (p_to VARCHAR2,
p_from IN VARCHAR2,
p_subject IN VARCHAR2,
p_message IN VARCHAR2,
p_attachment IN BLOB,
p_notes IN CLOB,
p_smtp_host IN VARCHAR2,
p_smtp_port IN NUMBER DEFAULT 25)
AS
l_mail_conn UTL_SMTP.connection;
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_TCP.crlf);
UTL_SMTP.write_data(l_mail_conn, p_message || UTL_TCP.crlf || UTL_TCP.crlf);
UTL_SMTP.close_data(l_mail_conn);
UTL_SMTP.quit(l_mail_conn);
END;
/
What I am trying to implement :
I need to iterate through my table EMPLOYEE and read one by one email id's and send email to them.
Need to write some for loop to iterate the employee table ? and shoot mail to them with details entered in components along with that if attachment if choosen [optional] : SUBJECT , NOTES , ATTACHMENT
I have 700+ email ids
Need to send all of them same details over their mail one by one reading from table EMPLOYEE

UTL_SMTP service not available error

I am getting service not available message when I am sending mail with large size attachment.
The requirement is to write a procedure which will extract the data of the whole table and send the extract as excel attachment in mail. table_name and email id will be passed as a parameter.
I tried with the CLOB. fetched the data from the table and put it into a CLOB as an XML structure. Then I am sending the mail with attachment as xls with the data present in CLOB.
For a lesser number of records(max around 2k) is working fine. But when I am checking for more number of records, the program is throwing an error of UTL_SMTP transient error - Service not available.
Following is the part of code where I am utilising UTL_SMTP.
BEGIN
vsql := 'SELECT * from test_table';
V_CLOB := get_query_output(vsql);
v_lob := v_clob;
v_connection := UTL_SMTP.open_connection('abcd.efgh.com');
UTL_SMTP.helo(v_connection, 'abcd.efgh.com');
UTL_SMTP.mail(v_connection, p_from);
UTL_SMTP.rcpt(v_connection, p_to);
UTL_SMTP.open_data(v_connection);
UTL_SMTP.write_data(v_connection, 'From: ' || p_from || UTL_TCP.crlf);
UTL_SMTP.WRITE_DATA(V_CONNECTION, 'To: ' || P_TO || UTL_TCP.CRLF);
utl_smtp.write_data(v_connection, 'Cc: ' || p_cc || utl_tcp.crlf);
UTL_SMTP.write_data(v_connection,
'Subject: NPI Error Report' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, 'MIME-Version: 1.0' || UTL_TCP.crlf);
DBMS_OUTPUT.PUT_LINE('at position 4');
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="' ||
'Error_Report.xls' || '"' || UTL_TCP.crlf);
UTL_SMTP.write_data(v_connection, UTL_TCP.crlf);
-- start attachment
V_LEN := DBMS_LOB.GETLENGTH(V_CLOB);
DBMS_OUTPUT.PUT_LINE('V_LEN :=' || V_LEN);
for I in 0 .. TRUNC((V_LEN - 1) / V_INDEX) LOOP
UTL_SMTP.WRITE_DATA(v_connection,
DBMS_LOB.SUBSTR(V_LOB, V_INDEX, I * V_INDEX + 1));
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);
UTL_SMTP.close_data(v_connection); UTL_SMTP.quit(v_connection);
EXCEPTION WHEN OTHERS THEN
BEGIN
UTL_SMTP.QUIT(v_connection);
raise;
END;
END;
Error Codes which I am getting when there are huge records(almost >2k) in the table:
enter image description here
Error report -
ORA-29277: invalid SMTP operation
ORA-06512: at "SYS.UTL_SMTP", line 82
ORA-06512: at "SYS.UTL_SMTP", line 212
ORA-06512: at "SYS.UTL_SMTP", line 622
ORA-06512: at "SYS.UTL_SMTP", line 633
ORA-06512: at line 328
ORA-29278: SMTP transient error: 421 Service not available
29277. 00000 - "invalid SMTP operation"
*Cause: The SMTP operation was invalid at the current stage of the SMTP
transaction.
*Action: Retry the SMTP operation at the appropriate stage of the SMTP
transaction.
The error is strange, usually this is not related to size of attached file.
Maybe your attachment causes problems with special characters, try to send the mail like this:
ClobLen PLS_INTEGER;
amount BINARY_INTEGER := 8192;
buffer VARCHAR2(16384);
offset PLS_INTEGER := 1;
BEGIN
....
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, '--'||C_MIME_BOUNDARY || Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'Content-Type: text/plain; name="Error_Report.xls"'|| Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'Content-Disposition: attachment; filename="Error_Report.xls"'|| Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
offset := 1;
ClobLen := DBMS_LOB.GETLENGTH(V_LOB);
LOOP
EXIT WHEN offset > ClobLen;
DBMS_LOB.READ(V_LOB, amount, offset, BUFFER);
UTL_SMTP.write_raw_data(con, Utl_Raw.cast_to_raw(BUFFER));
offset := offset + amount;
END LOOP;
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, '--'||C_MIME_BOUNDARY||'--' || Utl_Tcp.CRLF);
Perhaps the error is not caused by main block but by exception handler. Change your exception handler from
EXCEPTION WHEN OTHERS THEN
BEGIN
UTL_SMTP.QUIT(v_connection);
raise;
END;
END;
to
EXCEPTION
WHEN UTL_SMTP.TRANSIENT_ERROR OR UTL_SMTP.PERMANENT_ERROR THEN
UTL_SMTP.quit(v_connection);
RAISE;
END;

How to send email using Oracle 10 g Forms

i make a form i want when i click on button it send email i get a code for email from internet
CREATE OR REPLACE FUNCTION FSC.SEND_MAIL
(pIssuer IN VARCHAR2,
pReceiver IN VARCHAR2,
pSender IN VARCHAR2,
pSubject IN VARCHAR2,
pMessage IN VARCHAR2) RETURN VARCHAR2 IS
c utl_smtp.connection;
respuesta utl_smtp.reply;
pServer VARCHAR2(50) := '192.168.0.6';
BEGIN
-- Open the connection to the mail server
c := utl_smtp.open_connection(pServer);
respuesta := utl_smtp.helo(c, pServer);
-- Start the Issuer mail.
respuesta := utl_smtp.mail(c, pSender);
-- Starts Receiver
respuesta := utl_smtp.rcpt(c, pReceiver);
respuesta := utl_smtp.open_data(c);
-- Enter the email header
utl_smtp.write_data(c, 'From: ' || pIssuer || utl_tcp.CRLF);
utl_smtp.write_data(c, 'To: ' || pReceiver || utl_tcp.CRLF);
-- Enter the Subject
utl_smtp.write_data(c, 'Subject: ' || pSubject || utl_tcp.CRLF);
-- Write the message text.
utl_smtp.write_data(c, utl_tcp.CRLF || pMessage);
utl_smtp.write_data(c, utl_tcp.CRLF || '.');
respuesta := utl_smtp.close_data(c);
-- Close connection
respuesta := utl_smtp.quit(c);
RETURN '0';
EXCEPTION
WHEN utl_smtp.transient_error OR utl_smtp.permanent_error THEN
utl_smtp.quit(c);
RETURN sqlerrm;
--raise_application_error(-20000,
-- 'The sending of the email has failed by returning the following error: ' || sqlerrm);
WHEN OTHERS THEN
RETURN sqlerrm;
END;
/
i make this function in sql it and it was successfully run but when i execute then no email send to my desire address
declare
begin
dbms_output.put_line(SEND_MAIL('usmanafb#ctm.com.pk','usmanafb#ctm.com.pk','usmanafb#ctm.com.pk','Testing','email message'));
end;
i use my local exchange for eamil sending and the ip address of that server is 192.168.0.6
the second issue in this code when i make same function in Oracle 10 g forms then it give me this error
utl_tcp.CRLF is can not directly acces remote package
I use this general procedure to send out mails. It also supports attachment (plain text only) and mails are not limited to 32767 characters.
If you don't need attachments at all, it should be no problem for you to remove it.
PRIORITY_HIGH CONSTANT INTEGER := 1;
PRIORITY_NORMAL CONSTANT INTEGER := 3;
PRIORITY_LOW CONSTANT INTEGER := 5;
PROCEDURE SendMail(
Subject IN VARCHAR2,
Message IN OUT CLOB,
ToMail IN VARCHAR2,
FromMail IN VARCHAR2, FromName IN VARCHAR2,
Attachment IN OUT CLOB, FileName IN VARCHAR2,
Priority IN INTEGER DEFAULT PRIORITY_NORMAL) IS
MIME_BOUNDARY CONSTANT VARCHAR2(50) := '====Multipart.Boundary.689464861147414354====';
MIME_MIXED CONSTANT VARCHAR2(50) := 'multipart/mixed;';
MIME_TEXT CONSTANT VARCHAR2(50) := 'text/plain;';
MIME_HTML CONSTANT VARCHAR2(50) := 'text/html;';
MAIL_HOST CONSTANT VARCHAR2(50) := '192.168.0.6'; -- try also 'mailhost'
con UTL_SMTP.connection;
ret UTL_SMTP.reply;
Charset VARCHAR2(20);
Footer VARCHAR2(1000);
ClobLen PLS_INTEGER;
amount BINARY_INTEGER := 8192;
buffer VARCHAR2(16384);
offset PLS_INTEGER := 1;
isHTML BOOLEAN := REGEXP_LIKE(DBMS_LOB.SUBSTR(Message, 1000, 1), '<(html)|(body)', 'i');
BEGIN
SELECT UTL_I18N.MAP_CHARSET(VALUE)
INTO Charset
FROM V$NLS_PARAMETERS
WHERE PARAMETER = 'NLS_CHARACTERSET';
-- setup mail header
con := UTL_SMTP.OPEN_CONNECTION(MAIL_HOST, 25);
ret := UTL_SMTP.helo(con, SYS_CONTEXT('USERENV', 'DB_DOMAIN')); -- assuming your database is in the same domain as your mail server
ret := UTL_SMTP.Mail(con, FromMail);
ret := UTL_SMTP.rcpt(con, ToMail);
-- simply call "UTL_SMTP.rcpt(con, ...);" again in order to add further recipient
ret := UTL_SMTP.open_data(con);
IF FromName IS NOT NULL THEN
UTL_SMTP.write_data(con, 'From: "'||FromName||'" <'||FromMail||'>'||Utl_Tcp.CRLF);
ELSE
UTL_SMTP.write_data(con, 'From: <'||FromMail||'>'||Utl_Tcp.CRLF);
END IF;
UTL_SMTP.write_data(con, 'To: <'||ToMail||'>'||Utl_Tcp.CRLF);
-- UTL_SMTP.write_data(con, 'Cc: <'||CcMail||'>'||Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'Subject: '||Subject||Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'X-Priority: '||Priority||Utl_Tcp.CRLF);
IF Attachment IS NOT NULL AND FileName IS NOT NULL THEN
UTL_SMTP.write_data(con, 'Mime-Version: 1.0' || Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'Content-Type: '||MIME_MIXED||' boundary="'||MIME_BOUNDARY||'"' || Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'This is a multipart message in MIME format.' || Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, '--'||MIME_BOUNDARY || Utl_Tcp.CRLF);
END IF;
Footer := 'Message from '||SYS_CONTEXT('USERENV', 'DB_NAME')||' sent at '||TO_CHAR(SYSDATE,'yyyy-mm-dd hh24:mi:ss');
IF isHTML THEN
UTL_SMTP.write_data(con, 'Content-type: '||MIME_HTML||' charset='||Charset || Utl_Tcp.CRLF);
Message := REPLACE(message, '</body>', '<p>'||Footer||'</p></body>');
ELSE
UTL_SMTP.write_data(con, 'Content-type: '||MIME_TEXT||' charset='||Charset || Utl_Tcp.CRLF);
END IF;
-- Mail Body
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
ClobLen := DBMS_LOB.GETLENGTH(Message);
LOOP
EXIT WHEN offset > ClobLen;
DBMS_LOB.READ(Message, amount, offset, BUFFER);
UTL_SMTP.write_raw_data(con, UTL_RAW.cast_to_raw(BUFFER));
offset := offset + amount;
END LOOP;
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
IF NOT isHTML THEN
UTL_SMTP.write_data(con, Utl_Tcp.CRLF || Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, Footer);
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
END IF;
IF Attachment IS NOT NULL AND FileName IS NOT NULL THEN
-- Mail Attachment
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, '--'||MIME_BOUNDARY || Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'Content-Type: '||MIME_TEXT||' name="'||Filename||'"'|| Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'Content-Disposition: attachment; filename="'||Filename||'"'|| Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
offset := 1;
ClobLen := DBMS_LOB.GETLENGTH(Attachment);
LOOP
EXIT WHEN offset > ClobLen;
DBMS_LOB.READ(Attachment, amount, offset, BUFFER);
UTL_SMTP.write_raw_data(con, Utl_Raw.cast_to_raw(BUFFER));
offset := offset + amount;
END LOOP;
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, '--'||MIME_BOUNDARY||'--' || Utl_Tcp.CRLF);
END IF;
-- finish mail
ret := UTL_SMTP.close_data(con);
ret := UTL_SMTP.quit(con);
EXCEPTION
WHEN UTL_SMTP.TRANSIENT_ERROR OR UTL_SMTP.PERMANENT_ERROR THEN
UTL_SMTP.quit(con);
RAISE;
END SendMail;
Just a note, do not miss the UTL_SMTP.write_data(con, UTL_TCP.CRLF) lines. They are looking redundant, however most of them are required! Also courtesy message like "This is a multipart message in MIME format." is needed for proper display of your mail in case of attachments.
If you still face problems make a dbms_output.put_line(ret.code||': '||ret.text); after each function call on UTL_SMTP.
Here the same procedure but reduced to your needs:
FUNCTION SendMail(
Subject IN VARCHAR2,
Message IN VARCHAR2,
FromMail IN VARCHAR2, FromName IN VARCHAR2,
ToMail IN VARCHAR2) RETURN VARCHAR2 IS
MIME_TEXT CONSTANT VARCHAR2(50) := 'text/plain;';
MIME_HTML CONSTANT VARCHAR2(50) := 'text/html;';
MAIL_HOST CONSTANT VARCHAR2(50) := '192.168.0.6'; -- try also 'mailhost'
con UTL_SMTP.connection;
ret UTL_SMTP.reply;
Charset VARCHAR2(20);
isHTML BOOLEAN := REGEXP_LIKE(DBMS_LOB.SUBSTR(Message, 1000, 1), '<(html)|(body)', 'i');
BEGIN
SELECT UTL_I18N.MAP_CHARSET(VALUE)
INTO Charset
FROM V$NLS_PARAMETERS
WHERE PARAMETER = 'NLS_CHARACTERSET';
-- setup mail header
con := UTL_SMTP.OPEN_CONNECTION(MAIL_HOST, 25);
ret := UTL_SMTP.helo(con, SYS_CONTEXT('USERENV', 'DB_DOMAIN')); -- assuming your database is in the same domain as your mail server
ret := UTL_SMTP.Mail(con, FromMail);
ret := UTL_SMTP.rcpt(con, ToMail);
ret := UTL_SMTP.open_data(con);
UTL_SMTP.write_data(con, 'From: "'||FromName||'" <'||FromMail||'>'||Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'To: <'||ToMail||'>'||Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'Subject: '||Subject||Utl_Tcp.CRLF);
UTL_SMTP.write_data(con, 'X-Priority: 3'||Utl_Tcp.CRLF);
IF isHTML THEN
UTL_SMTP.write_data(con, 'Content-type: '||MIME_HTML||' charset='||Charset || Utl_Tcp.CRLF);
ELSE
UTL_SMTP.write_data(con, 'Content-type: '||MIME_TEXT||' charset='||Charset || Utl_Tcp.CRLF);
END IF;
-- Mail Body
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
UTL_SMTP.write_raw_data(con, UTL_RAW.cast_to_raw(Message));
UTL_SMTP.write_data(con, Utl_Tcp.CRLF);
-- finish mail
ret := UTL_SMTP.close_data(con);
ret := UTL_SMTP.quit(con);
RETURN '0';
EXCEPTION
WHEN UTL_SMTP.TRANSIENT_ERROR OR UTL_SMTP.PERMANENT_ERROR THEN
UTL_SMTP.quit(con);
RETURN SQLERRM;
END SendMail;

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.

How to sent email in Oracle PL/SQL package to multiple receivers?

How to sent email in Oracle PL/SQL package to multiple receivers? I have below pl/sql procedure within an oracle package, it works only for one receiver. I need to improve it functional to let it can send email to multiple receivers at same time like "To: David Festool; Peter Makita; John Dewalt". Any body can help me out will be great appreciate! Please provide me modified code.
procedure email(p_recip in varchar2,
p_subject in varchar2,
p_message in varchar2) is
c utl_smtp.connection;
msg varchar2(4000);
procedure send_header(name in varchar2, header in varchar2) as
begin
utl_smtp.write_data(c, name || ': ' || header || utl_tcp.crlf);
end;
begin
--Open SMTP connection
c := utl_smtp.open_connection('ExchangeServerName');
-- Write SMTP header
utl_smtp.helo(c, 'ExchangeServerName');
utl_smtp.mail(c, 'Email#MyCompany.on.ca');
utl_smtp.rcpt(c, p_recip);
utl_smtp.open_data(c);
send_header('From', '"Title" <Email#MyCompany.on.ca');
send_header('To', p_recip);
send_header('Subject', p_subject);
send_header('Mime-Version', '1.0');
send_header('Content-Type', 'multipart/mixed; boundary="DMW.Boundary.605592468"');
-- Write MIME boundary line for the message body
msg := utl_tcp.crlf || '--DMW.Boundary.605592468' || utl_tcp.crlf ||
'Content-Type: text/plain' || utl_tcp.crlf ||
'Content-Transfer-Encoding: 7bit' || utl_tcp.crlf ||
utl_tcp.crlf;
utl_smtp.write_data(c, msg);
-- Write message body
utl_smtp.write_data(c, p_message || utl_tcp.crlf);
-- Clean up
utl_smtp.close_data(c);
utl_smtp.quit(c);
exception
when utl_smtp.transient_error or utl_smtp.permanent_error then
begin
utl_smtp.quit(c);
exception
when utl_smtp.transient_error or utl_smtp.permanent_error then
null;
-- When the SMTP server is down or unavailable, we don't have
-- a connection to the server. The QUIT call will raise an
-- exception that we can ignore.
end;
raise_application_error(-20000, 'Failed to send mail due to the following error: ' ||
sqlerrm);
end;
--------------------------------------------------------------
You need to call utl_smtp.rcpt multiple times, once for each recipient; you can't give a list of values in one call.
From the UTL_SMTP.RCPT documentation:
To send a message to multiple recipients, call this routine multiple
times. Each invocation schedules delivery to a single e-mail address.
That means you can't really pass a string of names, unless you're happy to parse the individual addresses out; it would be easier to pass an array of values, probably.
The TO header is a separate issue; if I recall correctly, that is really just for display, and having an address as a rcpt but not in the TO (or CC) header is how BCC is implemented. Citation needed though...
Here's an old AskTom article demonstrating this. jonearles suggestion to use UTL_MAIL should be investigated though.
The format is:
UTL_MAIL.SEND (sender, recipientlist, cc, bcc, subject, Message, mime_type, priority)
The recipientlist, cc, and bcc parameters are all comma-separated lists of recipient, copy to, and blind copy e-mail addresses.
The sender, subject, message, and mime_type parameters are all single item fields.
Just run below procedure with change code:
v_Mail_Host VARCHAR2(50) := 'uacemail.rxcorp.com'; -- your host ip or name
Execute:
begin prc_email_send( 'sohid10#yahoo.com', -- Mail From
'smolla#bd.imshealth.com',---Recipient
'sohidatibd#gmail.com;smokarem#bd.imshealth.com',-- Cc List
'This is mail subject ', 'This is mail body' );
end; /
Procedure Code:
Create or replace procedure prc_email_send(
v_From VARCHAR2,
v_Recipient VARCHAR2,
v_cc_list varchar2,
v_Subject VARCHAR2,
v_Mail_body VARCHAR2
)
is
v_Mail_Host VARCHAR2(50) := 'uacemail.rxcorp.com';
v_Mail_Conn utl_smtp.Connection;
crlf VARCHAR2(2) := chr(13)||chr(10);
CC_parties varchar2(2000);
begin
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 i in (SELECT LEVEL AS id, REGEXP_SUBSTR(v_cc_list, '[^;]+', 1, LEVEL) AS cc_email_name
FROM dual
CONNECT BY REGEXP_SUBSTR(v_cc_list, '[^;]+', 1, LEVEL) IS NOT NULL) loop
CC_parties := CC_parties||';'|| i.cc_email_name;
utl_smtp.Rcpt(v_Mail_Conn,i.cc_email_name);
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 ||
'Cc: ' || CC_parties|| crlf ||
'Content-Type: text/html;' ||crlf ||
v_Mail_body);
utl_smtp.Quit(v_mail_conn);
EXCEPTION
WHEN OTHERS THEN
BEGIN
DBMS_OUTPUT.put_line (
SUBSTR (
'Unable to send mail to recipients. Error message: '
|| SQLERRM
|| CHR (10)
|| DBMS_UTILITY.FORMAT_ERROR_BACKTRACE (),
1,255));
UTL_SMTP.quit (v_Mail_Conn);
UTL_TCP.close_all_connections;
EXCEPTION
WHEN UTL_SMTP.transient_error OR UTL_SMTP.permanent_error THEN
NULL;
END;
END;
This is working fine for myself

Resources