Execute Shell Command for sending mail from PL/SQL - oracle

We are forced to use mailx command from PL/SQL for sending mail.
Actually I have the generic script with me, but I am not sure how to execute directly in the PL/SQL code.
The code we have is
(echo "$mailbody" uuencode $ZIP_FILE $ZIP_FILE) | mailx -m -s "subject" -r " " "$mail_to_address"

Obviously you've explained that Oracle has built-in support through UTL_MAIL and it's foolhardy to not use the functionality your organization has already paid for :)
" I am not sure how to execute directly in the PL/SQL code"
You can't run OS commands directly from PL/SQL. However...
Since Oracle 10g, DBMS_SCHEDULER has allowed us to call host programs. CREATE_PROGRAM() where program_type => 'EXECUTABLE'. The scheduler approach would be the best approach if you want to have a background job which polls for notifications and then sends batches of emails. Frankly the best intro the DBMS_SCHEDULER is Tim Hall's articles on Oracle-Base.
But if you need on-demand execution of calls then the approach you need is a Java Stored Procedure which uses a Java Command object to run host calls. There can be political issues with this, because some DBAs are suspicious of Java, but it's supported. Here's an Oracle White Paper which explains how to go about it.

You can send email from a PL/SQL procedure without invoking an OS command like mailx. Some examples are here:
http://www.orafaq.com/wiki/Send_mail_from_PL/SQL
Example code from one of the examples:
DECLARE
v_From VARCHAR2(80) := 'oracle#mycompany.com';
v_Recipient VARCHAR2(80) := 'test#mycompany.com';
v_Subject VARCHAR2(80) := 'test subject';
v_Mail_Host VARCHAR2(30) := 'mail.mycompany.com';
v_Mail_Conn utl_smtp.Connection;
crlf VARCHAR2(2) := chr(13)||chr(10);
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);
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 ||
crlf ||
'some message text'|| crlf || -- Message body
'more message text'|| crlf
);
utl_smtp.Quit(v_mail_conn);
EXCEPTION
WHEN utl_smtp.Transient_Error OR utl_smtp.Permanent_Error then
raise_application_error(-20000, 'Unable to send mail', TRUE);
END;
/

Related

PL/SQL character buffer overflow in UTL_SMTP

I have a PL/SQL sproc which sends an email, with addressee and such as parameters. We recently migrated it, to a new environment, and switched it from using an internal mail server to using Office 365. In order to do this I needed to upgrade it to use TLS/SSL, which is now working. But it's getting a weird error now.
All of the authentication code works fine, I can transmit the auth, and all the message data, with no issue. But when i call UTL_SMTP.CLOSE_DATA, it throws ORA-06502: PL/SQL: numeric or value error: character string buffer too small.
This section of the code is unchanged from the old environment, where it was working without issue. By this point, I've already concatenated my variables, so I know it's not an issue with my variable sizes. It seems to be something inside the UTL_SMTP package, but that seems to be a compiled package, so I can't even view the stack source to try to figure out what or where the issue is.
Below is our sproc code...
CREATE OR REPLACE PROCEDURE ourschema.SENDMAILTLS
(
vSENDER IN VARCHAR2,
vSENDEE IN VARCHAR2,
vSUBJECT IN VARCHAR2,
vMESSAGE IN VARCHAR2
) AS
vMAILHOST VARCHAR2(255) := ourschema.GETOPTION('SMTPSRV');
oSMTP UTL_SMTP.connection;
vCRLF VARCHAR2(2) := chr(13) || chr(10);
vDATA VARCHAR2(32767);
BEGIN
vDATA := 'Subject:' || vSUBJECT || vCRLF;
vDATA := vDATA || 'Date:' || to_char(SYSDATE, 'Dy, DD Mon YYYY hh24:mi:ss') || vCRLF;
vDATA := vDATA || 'From:' || vSENDER || vCRLF;
vDATA := vDATA || 'Content-Type:text; charset=us-ascii' || vCRLF;
vDATA := vDATA || 'Reply-To:' || vSENDER || vCRLF;
vDATA := vDATA || 'Sender:' || vSENDER || vCRLF;
vDATA := vDATA || vCRLF;
vDATA := vDATA || vMESSAGE || vCRLF;
vDATA := vDATA || vCRLF;
ourschema.LOG('TLS Email sending from ' || vSENDER || ' to ' || vSENDEE || ' via ' || vMAILHOST || '.', vDATA);
utl_tcp.close_all_connections();
oSMTP := UTL_SMTP.open_connection(vMAILHOST, TO_NUMBER(ourschema.GETOPTION('SMTPPORT')), wallet_path => 'file:O:\ur\Wallet\Path', wallet_password => 'OurWalletPassword');
UTL_SMTP.EHLO(oSMTP, vMAILHOST);
UTL_SMTP.STARTTLS(oSMTP);
UTL_SMTP.EHLO(oSMTP, vMAILHOST);
UTL_SMTP.AUTH(oSMTP, 'U******', 'P******', UTL_SMTP.ALL_SCHEMES);
UTL_SMTP.mail(oSMTP, ourschema.GETOPTION('SMTPADDR'));
UTL_SMTP.rcpt(oSMTP, vSENDEE);
UTL_SMTP.open_data(oSMTP);
UTL_SMTP.write_data(oSMTP, vDATA);
UTL_SMTP.close_data(oSMTP);
UTL_SMTP.quit(oSMTP);
ourschema.LOG('TLS Email sent successfully from ' || vSENDER || ' to ' || vSENDEE || ' via ' || vMAILHOST || '.', vDATA);
END;
The line it is failing on is
UTL_SMTP.close_data(oSMTP);
And this is the test script I'm using. No massive amounts of data that would blow anything out.
begin
-- Call the procedure
idsystem.SENDMAILTLS(vSENDER => 'notifications#ourdomain.com',
vSENDEE => 'myemail#ourdomain.com',
vSUBJECT => 'Testing Oracle Email',
vMESSAGE => 'Did you get this yet?');
end;
And here's the error message... with the stack trace showing it's coming from somewhere deep in the UTL_SMTP package.
But if I say Yes to view the stack source, this is all that comes up for the UTL_SMTP package... so I can't even begin to make heads or tails of how I may be offending it.
Oracle version is 12c Standard, 12.2.0.1.0
Based on the stack trace it looks like the receiver end is sending data greater than 512 characters. This means basically the e-mail that you are sending might have some issue that generates huge data as a response.
The problem might be
recepeint email id is nonexistent
Email attachment is invalid etc
ourschema.GETOPTION('SMTPADDR') should be a valid sender
To understand the issue try sending the same email from your email application and if it success and doesn't generate a large response then please check your configuration.

Cyrillic characters are distorted when sending a letter

When ending a letter to Outlook mail from an Oracle DBMS that contains Cyrillic characters, the output is question marks. I do not understand how to convert the string so that the text is readable. I ship using the following method:
CREATE OR REPLACE PROCEDURE send_mail (p_to IN VARCHAR2,
p_from IN VARCHAR2,
p_message IN VARCHAR2,
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.data(l_mail_conn, 'Привет мир!' || UTL_TCP.crlf || UTL_TCP.crlf);
UTL_SMTP.quit(l_mail_conn);
END;
I use Oracle Database 10g Release 10.2.0.3.0 - Production
You need to add lines like this:
SELECT UTL_I18N.MAP_CHARSET(VALUE)
INTO Charset
FROM NLS_DATABASE_PARAMETERS
WHERE parameter = 'NLS_CHARACTERSET';
UTL_SMTP.WRITE_DATA(l_mail_conn, 'Content-Type: text/plain; charset='||Charset || UTL_TCP.CRLF);
By this you tell the mail server/client which character set is used in the mail.
The mail subject does not natively support Non-ASCII characters. You need to encode it like this (see. RFC1342):
UTL_SMTP.WRITE_DATA(con, 'Subject: =?UTF-8?B?'|| UTL_ENCODE.TEXT_ENCODE('Привет мир!', 'AL32UTF8', UTL_ENCODE.BASE64) ||'?='||UTL_TCP.CRLF);
See how to export data from log table to email body in oracle to get a more advanced and complete solution.

Error Happend after calling send mail procedure

I have created a procedure named as send_mail in sql developer oracle which is written below.
create or replace procedure Send_Mail(Msg_To varchar2, Msg_Subject varchar2, Msg_Text varchar2) is
c Utl_Smtp.Connection;
Rc integer;
Msg_From varchar2(50) := 'it.dev23#dawateislami.net'; -- email of my company which hosted on Gmail
Mailhost varchar2(30) := 'smtp.gmail.com';
begin
c := Utl_Smtp.Open_Connection(Mailhost, 587);
Utl_Smtp.Ehlo(c, Mailhost);
Utl_Smtp.StartTLS(c);
Utl_Smtp.Ehlo(c, Mailhost);
Utl_Smtp.Mail(c, Msg_From);
Utl_Smtp.Rcpt(c, Msg_To);
Utl_Smtp.Data(c,
'From: Oracle Database' || Utl_Tcp.Crlf || 'To: ' || Msg_To || Utl_Tcp.Crlf || 'Subject: ' || Msg_Subject || Utl_Tcp.Crlf ||
Msg_Text);
Utl_Smtp.Quit(c);
exception
when Utl_Smtp.Invalid_Operation then
Dbms_Output.Put_Line(' Invalid Operation in Mail attempt
using UTL_SMTP.');
when Utl_Smtp.Transient_Error then
Dbms_Output.Put_Line(' Temporary e-mail issue - try again');
when Utl_Smtp.Permanent_Error then
Dbms_Output.Put_Line(' Permanent Error Encountered.');
end;
And when i am trying to call the procedure to send email it gives error please help me out i want to send email .let me know where is my mistake.
I have grant all commands
GRANT EXECUTE ON UTL_TCP TO admonline;
GRANT EXECUTE ON UTL_SMTP TO admonline;
GRANT EXECUTE ON UTL_MAIL TO admonline;
GRANT EXECUTE ON UTL_http TO admonline;
--Calling procedure
BEGIN
send_mail(msg_to => 'waqasprince911#gmail.com',
msg_subject => 'Test subject',
msg_text => 'Test text');
END;
Error is Mention
Certificate validation failure
ORA-06512: at "SYS.UTL_TCP", line 59
ORA-06512: at "SYS.UTL_TCP", line 284
ORA-06512: at "SYS.UTL_SMTP", line 284
ORA-06512: at "SYS.UTL_SMTP", line 289
ORA-06512: at "ADMONLINE.SEND_MAIL", line 11
ORA-06512: at line 2
29024. 00000 - "Certificate validation failure"
*Cause: The certificate sent by the other side could not be validated. This may occur if
the certificate has expired, has been revoked, or is invalid for another reason.
*Action: Check the certificate to determine whether it is valid. Obtain a new certificate,
alert the sender that the certificate has failed, or resend.
The error seems pretty clear. Try googliing for UTL_SMTP , certificate and 29024. 00000 - "Certificate validation failure" also read the docs on how to use this package. It would seem to be a failure of the security certificate.
A quick google turned up this,
Also, as a noob, remember you are asking us to take time out of our day to help you. Help us by always including version of product and what steps you have tried and the result and what searches and investigation you have tried.
these may help:
https://mathijsbruggink.com/2013/10/24/sending-mail-from-an-11g-oracle-database-utl_smtp/ https://community.oracle.com/thread/930797 http://www.dadbm.com/enable-oracle-database-to-send-emails-via-smtp-server/ https://community.oracle.com/thread/368259
https://community.oracle.com/thread/4089002 https://oracle-base.com/articles/misc/utl_http-and-ssl
https://docs.oracle.com/database/121/ARPLS/u_smtp.htm#ARPLS074
https://oracle-base.com/articles/misc/email-from-oracle-plsql

Getting error ORA-00933 with execute immediate update

I have to write a function which edits predefined characteristics of a task. I'm using execute immediate but I'm getting this error:
> Error report -
ORA-00933: SQL command not properly ended
ORA-06512: at "C##U1519.BEARBEITE", line 7
ORA-06512: at line 2
00933. 00000 - "SQL command not properly ended"
This is my code
create or replace procedure bearbeite(Aufg_ID Aufgabe.Aufgaben_ID%TYPE, Eigenschaft VARCHAR2, Wert VARCHAR2)
as
sql_query_string2 VARCHAR2(4000);
begin
--überprüfen
sql_query_string2 := 'UPDATE Aufgabe SET ' || Eigenschaft || ' = ' || Wert || ' where Aufgabe.Aufgaben_ID = ' || Aufg_ID;
EXECUTE IMMEDIATE sql_query_string2;
exception
when no_data_found then
dbms_output.put_line('Kein Wert');
end;
-- test
set serveroutput on
begin
bearbeite(1,'Ort','TH WILDAU');
end;
What should I do in order to make it work? Thanks in advance
Dumping values into query strings is dangerous. The most advertised danger is SQL injection, but that doesn't apply in many cases (where user input might have controls already in place). A bigger issue is unexpected syntax errors. More than one person -- I'm sure -- has encountered a name like O'Neil to their detriment when generating a query string.
I strongly recommend the use of parameters. And this is easy in Oracle:
sql_query_string2 := 'UPDATE Aufgabe SET ' || Eigenschaft || ' = :1 where Aufgabe.Aufgaben_ID = :2';
EXECUTE IMMEDIATE sql_query_string2 USING Wert, Aufg_ID;
This also means that you don't have to worry about whether or not to use single quotes.
The parameters can be named rather than numbered.
Sadly, you cannot use parameters for SQL identifiers -- table names, schema names, column names, functions, key words. So, the column name does have to be incorporated into the string.
You should surround varchar2 argument with single quotes ... which in pl/sql should be escaped and becomes ''
sql_query_string2 := 'UPDATE Aufgabe SET ' || Eigenschaft || ' = ''' || Wert || ''' where Aufgabe.Aufgaben_ID = ' || Aufg_ID;

Sending multiple emails using UTL_SMTP in oracle

I am trying to write a procedure which send emails from Oracle DB using UTL_SMTP functions. Its working fine if I am only sending one email address but if I am passing multiple emails as comma or semicollon(;), its failling with error like
ORA-29277: invalid SMTP operation
ORA-29279: SMTP permanent error: 501 5.1.3 Invalid address
I am writing the statement like :- where P_ALERT_DESTINATION is a variable which is having multiple emails id.
UTL_SMTP.WRITE_DATA(L_MAIL_CONN, 'To: ' || P_ALERT_DESTINATION || UTL_TCP.CRLF);
I think you need to loop all email addresses and make that procedure call to each one.
Pseudo code:
for all_addresses loop
UTL_SMTP.WRITE_DATA(L_MAIL_CONN, 'To: ' || one_address|| UTL_TCP.CRLF)
end loop;
Edited:
Here you go, this should work:
declare
cursor split_cursor(p_to in varchar2) is
select regexp_substr(p_to, '[^,]+', 1, level) email_address
from dual
connect by regexp_substr(p_to, '[^,]+', 1, level) is not null;
begin
for i in split_cursor(P_ALERT_DESTINATION) loop
UTL_SMTP.WRITE_DATA(L_MAIL_CONN, 'To: ' || i.email_address|| UTL_TCP.CRLF);
end loop;
end;
You should also remove all spaces if the variable contains those.

Resources