Cyrillic characters are distorted when sending a letter - oracle

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.

Related

Consuming rest API from Oracle PLSQL is returning ??? for arabic characters

I am trying to call a restful API from my Oracle procedure.
First, the API method is of type get and not post, so parameters are sent through header. the main purpose of the API is to send the received message as SMS to some providers and sometimes they are in Arabic format; We realized that Arabic received SMS are incomprehensible;
So I created a test procedure that takes a message and sends it to a test API method that returns the same message as response.
The API call succeeded but the response, only when arabic format is used, looks like ����. What should be added to my procedure so messages can be readable? I have tried to use escape for the message and to set the header format as you can see in below template, but unfortunately nothing succeeded:
PROCEDURE TEST(lang VARCHAR2,
message VARCHAR2,
P_RESPONSE OUT VARCHAR2) AS
v_request UTL_HTTP.req;
v_response UTL_HTTP.resp;
v_text VARCHAR2(1024);
v_url VARCHAR2(1024);
v_message VARCHAR2(1024);
l_webservice_link VARCHAR2(128);
BEGIN
BEGIN
P_RESPONSE := '';
v_message := utl_url.escape(message);
--v_message :=utl_url.escape(message,false,'UTF-8');
--v_message :=utl_url.escape(message,false,'windows-1256');
--v_message :=utl_url.escape(message,false,'AL32UTF8');
--v_message :=utl_url.escape(message,false,'AR8MSWIN1256');
l_webservice_link := GET_PARAM('REST_API_URL');
v_url := l_webservice_link ||
'Mytest?strMessage=' || v_message||
'&strLang=' || lang;
v_request := UTL_HTTP.begin_request(v_url);
--UTL_HTTP.set_header(v_request, 'Content-Type', 'charset=UTF-8');
--UTL_HTTP.set_header(v_request, 'Content-Type', 'windows-1256');
v_response := UTL_HTTP.get_response(v_request);
LOOP
BEGIN
UTL_HTTP.read_text(v_response, v_text);
DBMS_OUTPUT.put_line(v_text);
EXCEPTION
WHEN UTL_HTTP.end_of_body THEN
NULL;
END;
EXIT WHEN v_text IS NULL;
END LOOP;
UTL_HTTP.end_response(v_response);
IF v_response.status_code <> 200 THEN
P_RESPONSE := v_response.reason_phrase;
END IF;
EXCEPTION
WHEN OTHERS THEN
P_RESPONSE := 'An error has occured: ' || SQLERRM;
END;
END TEST;
Any help is more than appreciated.
Try to insert this code:
Charset VARCHAR2(20);
BEGIN
SELECT UTL_I18N.MAP_CHARSET(VALUE)
INTO Charset
FROM nls_database_parameters
WHERE parameter = 'NLS_CHARACTERSET';
UTL_HTTP.set_header(v_request, 'Content-Type', 'text/html; charset='||Charset);
I am not familiar with REST, I don't know wether text/html; is required and correct.
Update
I just see your database character set it AR8ASMO8X which does not have any IANA name (at least not according to Oracle UTL_I18N.MAP_CHARSET)
In this case try
UTL_HTTP.set_header(v_request, 'Content-Type', 'text/html; charset=UTF-8');
UTL_HTTP.begin_request(CONVERT(v_url,'AL32UTF8'));
Most likely the server returns response in UTF-8 - would be the most common one, otherwise check the header of the response.
Then try this:
UTL_HTTP.SET_BODY_CHARSET(v_response, 'AL32UTF8');
Apart from all above you may have also a display issue, i.e. inside Oracle everything would be fine, just your client is not able to display the characters properly, see OdbcConnection returning Chinese Characters as "?"

Execute Shell Command for sending mail from PL/SQL

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;
/

PLS-00306: wrong number or types of arguments in call to 'PUT_LINE'

This is the first time I have tried writing an Oracle procedure and I am getting an error (shown in the question title) centering on the DBMS_OUTPUT.PUT_LINE line.
I read online that it can only hand back VARCAHR2 columns, so I have cast the only two non VARCHAR2 columns that are being accessed, but I am still getting the error. This error is happening when I try to run it directly in the oracle SQL Developer.
CREATE OR REPLACE PROCEDURE LOGGING_PRC
(
STARTDATE_IN IN VARCHAR2,
ENDDATE_IN IN VARCHAR2,
NAMES_IN IN VARCHAR2,
MODS_IN IN VARCHAR2,
LOGS_IN IN VARCHAR2,
ID_OUT OUT VARCHAR2,
NAME_OUT OUT VARCHAR2,
MODULE_OUT OUT VARCHAR2,
ENTRYDATE_OUT OUT VARCHAR2,
STATUS_OUT OUT VARCHAR2,
TYPE_OUT OUT VARCHAR2
)
AS
BEGIN
SELECT
CAST(ID_LOG AS VARCHAR2(16)),
APNAME,
APPMOD,
CAST(ENTRYDATE AS VARCHAR2(30)),
APPSTATUS,
LOGTYPE
INTO
ID_OUT,
NAME_OUT,
MODULE_OUT,
ENTRYDATE_OUT,
STATUS_OUT,
TYPE_OUT
FROM
BASE
WHERE
ENTRYDATE > STARTDATE_IN AND
ENTRYDATE < ENDDATE_IN AND
(NAMES = NAMES_IN OR NAMES_IN IS NULL) AND
(MODS = MODS_IN OR MODS_IN IS NULL) AND
(LOGS = LOGS_IN OR LOGS_IN IS NULL);
RETURN;
DBMS_OUTPUT.PUT_LINE(ID_OUT, NAME_OUT, MODULE_OUT, ENTRYDATE_OUT, STATUS_OUT, TYPE_OUT);
END LOGGING_PRC;
Does someone see where I have the incorrect code?
DBMS_OUTPUT.PUT_LINE is defined as follows
procedure put_line(a varchar2);
so, it only accepts one input parameter.
If you need to print the values of more than one field, you need to concatenate them in a single varchar2; you can try with :
DBMS_OUTPUT.PUT_LINE(ID_OUT || ',' || NAME_OUT || ',' || MODULE_OUT || ',' || ENTRYDATE_OUT || ',' || STATUS_OUT || ',' || TYPE_OUT);

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.

How do I keep my UTF8 characers when sending email?

Oracle 11g. PL/SQL. Oracle uses AL32UTF8.
LastName
--------
Manaña
The unicode value in Oracle for the ñ is (00F1) the ascii value is (0241). When I send this value in an email. The email reads 'manan?a'.
The email value in HEX is (3F).
Question: How can I keep my 'ñ' when I send it via email?
Here's select dump:
select dump(last_name) => [Typ=1 Len=7: 77,97,110,97,195,177,97]
When I send the email, I call package.mail
Here's that snippet
last_name := 'Manaña'
packagename.mail(recipient ==>'emailrecipeint#blah.com',
subject ==>'Email Subject',
message ==>last_name);
PROCEDURE mail(sender IN VARCHAR2 default 'non-reply#company.edu',
recipients IN VARCHAR2,
subject IN VARCHAR2,
message IN VARCHAR2) IS
conn utl_smtp.connection;
userid varchar2(256);
globalname varchar2(256);
BEGIN
conn := begin_mail(sender, recipients, subject);
select global_name into globalname from global_name;
select user into userid from dual;
write_text(conn, message);
end_mail(conn);
END;
Here's the snippet for package.write_text
PROCEDURE write_text(conn IN OUT NOCOPY utl_smtp.connection,
message IN VARCHAR2) IS
BEGIN
utl_smtp.write_data(conn, message);
END;
Mail is fundamentally 7-bit. To send anything else than 7-bit text/plain, encapsulate and encode it using MIME. In your case, it's probably sufficient to delclare Content-Type: text/plain; charset="utf-8" and Content-Transfer-Encoding: quoted-printable. Then if course you need to QP-encode your text; your language probably has a library for this. (It's not hard to roll your own, but it's usually a bad idea.)

Resources