Sending mail from Oracle APEX PL/SQL code using an Apache proxy - oracle

I'm having problems sending mails from APEX, I'm using XAMPP, APEX is running on an Apache Tomcat server, and I'm Mercury SMTP to send the mails. The problem is when I execute the PL/SQL code it doesn't encounter any errors, but the emails don't show up in the APEX admin mail queue, nor do they arrive at the destination email address.
Here are the PL/SQL codes I tried using.
APEX_MAIL:
create or replace procedure PROC_SEND_MAIL(p_from varchar2, p_to varchar2, p_subject varchar2, p_body varchar2)
as
l_id number;
begin
l_id := APEX_MAIL.SEND(
p_to, p_from, p_subject, p_body);
APEX_MAIL.push_queue;
commit;
end PROC_SEND_MAIL;
UTL_SMTP:
create or replace PROCEDURE SEND_SMTP (msg_to varchar2, msg_subject varchar2, msg_text varchar2 )
IS
c utl_smtp.connection;
rc integer;
msg_from varchar2(50) := 'Sender';
mailhost VARCHAR2(30) := 'My apache proxy IP address';
BEGIN
c := utl_smtp.open_connection(mailhost, 25); -- SMTP on port 25
utl_smtp.helo(c, mailhost);
utl_smtp.mail(c, msg_from);
utl_smtp.rcpt(c, msg_to);
utl_smtp.data(c,'From: Sender' || 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 send_smtp;
Of course when I stop the Mercury SMTP I'm getting an error stating the service is not found, so I guess I configured the SMTP properly.
If it's a problem with the proxy, how do I configure the Apache httpd.conf file to know which emails should it serve?
Thanks in advance!
Regards,
Tamas

Related

Fix PL/SQL program that sends e-mail

The following PL/SQL program that sends email, which uses basic authentication to authenticate to sendgrid, was working until yesterday.
create or replace PROCEDURE ENVIA_EMAIL( p_remetente IN VARCHAR2
,p_destinatario IN VARCHAR2
,p_titulo_email IN VARCHAR2
,p_mensagem IN VARCHAR2
,p_dsc_arquivo_atachado1 IN VARCHAR2 DEFAULT NULL
,p_tipo_arquivo1 IN VARCHAR2 DEFAULT 'TEXT'
,p_dsc_arquivo_atachado2 IN VARCHAR2 DEFAULT NULL
,p_tipo_arquivo2 IN VARCHAR2 DEFAULT 'TEXT'
,p_dsc_arquivo_atachado3 IN VARCHAR2 DEFAULT NULL
,p_tipo_arquivo3 IN VARCHAR2 DEFAULT 'TEXT'
,p_username IN VARCHAR2
,p_password IN VARCHAR2) IS
--
-- Declaracao de variaveis
w_usuario NUMBER(10);
w_smtp_ip VARCHAR2(30) := 'smtp.sendgrid.net';
w_smtp_porta NUMBER := 587;
boundary CONSTANT VARCHAR2(256) := 'CES.Boundary.DACA587499938897';
w_conexao UTL_SMTP.CONNECTION;
w_mensagem VARCHAR2(30000);
w_nova_linha VARCHAR(2) := chr(13)||chr(10);
wrk_local NUMBER;
w_destinatario VARCHAR2(500);
w_destinatario_todo VARCHAR2(500);
w_destin_todo_fixo VARCHAR2(500);
TYPE varchar2_table IS TABLE OF VARCHAR2(256) INDEX BY BINARY_INTEGER;
w_contador BINARY_INTEGER;
function subject_encode(s_string varchar2) return varchar2 is
temp_subject varchar2(6000);
lengthsubject pls_integer:= 40;
w_nova_linha VARCHAR(2) := chr(13)||chr(10);
count_length pls_integer;
begin
count_length:=CEIL(LENGTH(s_string)/lengthsubject);
temp_subject:='=?iso-8859-1?B?' ||
utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(substr(s_string,1,lengthsubject ))))|| '?=';
for i in 2..count_length loop
temp_subject:=temp_subject||'=?iso-8859-1?B?'||
utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw( SUBSTR(s_string,1+(lengthsubject*(i-1)) ,lengthsubject ))))|| '?=';
end loop;
return temp_subject;
end;
BEGIN
w_destinatario_todo := p_destinatario||';';
w_destin_todo_fixo := p_destinatario;
LOOP
w_destinatario := substr(w_destinatario_todo,1,(instr(w_destinatario_todo,';')) - 1);
w_destinatario_todo := substr(w_destinatario_todo,(instr(w_destinatario_todo,';') + 1));
IF w_destinatario IS NOT NULL THEN
-- Abrindo Conexao SMTP e HTTP
w_conexao := utl_smtp.open_connection(w_smtp_ip,w_smtp_porta);
-- Comunicando SMTP
utl_smtp.helo(w_conexao, w_smtp_ip);
-- Autenticacao INICIO
utl_smtp.command(w_conexao,'AUTH LOGIN');
utl_smtp.command(w_conexao,utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(('username')))));
utl_smtp.command(w_conexao,utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(('password')))));
utl_smtp.mail(w_conexao,('<'||'myusername#myhost.com.br'||'>'));
utl_smtp.rcpt(w_conexao,('<'||w_destinatario||'>'));
utl_smtp.open_data (w_conexao);
-- Criando Cabeca do E-mail
w_mensagem := 'Date: '||TO_CHAR(SYSDATE,'dd Mon yy hh24:mi:ss')||w_nova_linha||
'From: '||p_remetente||w_nova_linha||
'To: '||w_destin_todo_fixo||w_nova_linha||
'Subject: '||subject_encode(p_titulo_email)||w_nova_linha;
--- 'To: '||w_destin_todo_fixo||w_nova_linha;
-- w_mensagem := w_mensagem || 'Mime-Version: 1.0' || w_nova_linha ||
-- 'Content-Type: multipart/mixed; boundary="' || boundary || '"' || w_nova_linha || w_nova_linha; --||
utl_smtp.write_data(w_conexao,w_mensagem);
--
IF p_mensagem IS not NULL THEN
w_mensagem := '--' || boundary || w_nova_linha ||
'Content-Type: text/html; charset=iso-8859-1' || w_nova_linha ||
'Content-Transfer-Encoding: base64' || w_nova_linha || w_nova_linha;
utl_smtp.write_data(w_conexao,w_mensagem);
utl_smtp.write_data(w_conexao,utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(p_mensagem)))|| w_nova_linha);
END IF;
-- Append the final boundary line
-- w_mensagem := w_nova_linha || '--' || boundary || '--' || w_nova_linha;
-- utl_smtp.write_data(w_conexao,w_mensagem);
-- Fechando conexao SMTP
utl_smtp.close_data(w_conexao);
utl_smtp.quit(w_conexao);
-- Insere um registro de emails.
BEGIN
w_usuario := substr(USER,2,50);
EXCEPTION
WHEN OTHERS THEN
w_usuario := 0;
END;
END IF;
IF w_destinatario_todo IS NULL THEN
EXIT;
END IF;
END LOOP;
END;
Yesterday sendgrid stopped supporting basic authentication. Now sendgrid require that an api key is used to authenticate.
I followed sendgrid instructions and created an api key via UI portal. Also, I replaced the username and password in the e-mail program with the values of "apikey"(username) and "actualKey"(password) according to sendgrid documentation as illustrated below.
utl_smtp.command(w_conexao,utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(('apikey')))));
utl_smtp.command(w_conexao,utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(('Sdyg.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')))));
However, I am getting the following error when attempting to send an e-mail.
"The provided authorization grant is invalid, expired or revoked"
Any advice on how I could fix that?
The issue was that a line break is added when the following is executed
select utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(('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')))) from dual;
the output is
U0cuNkU5TExrMHNUamZ0YzZxbG04ZXpnUS5raXhJd2RTSWV0RGE4d0ZUYnNNZHFf
Z1hWeVgxM3dtSHhGdlU5SHZmOTlv
To remove that line break, I modified that statement to look like that
select replace(replace(replace(utl_raw.cast_to_varchar2(utl_encode.base64_encode(utl_raw.cast_to_raw(('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')))),chr(10),' '),chr(13),' '),' ','') from dual;
the output is
U0cuNkU5TExrMHNUamZ0YzZxbG04ZXpnUS5raXhJd2RTSWV0RGE4d0ZUYnNNZHFfZ1hWeVgxM3dtSHhGdlU5SHZmOTlv

Oracle stored procedure called ok from local, but error from dblink

I have an Oracle Stored Procedure which compiled with no error, and runs with result I expected. Here's how I call it in local DB :
variable v_emp_cur refcursor;
exec my_schema.SP_READ_MEMBER('12345678', '', :v_emp_cur);
print v_emp_cur;
It printed result well. However, when I call this SP from another DB, using a dblink, like following :
variable v_emp_cur refcursor;
exec my_schema.SP_READ_MEMBER#my_dblink('12345678', '', :v_emp_cur);
print v_emp_cur;
It returns this error message :
BEGIN my_schema.sp_read_member#my_dblink('12345678', '', :v_emp_cur); END;
Error at line 2
ORA-00604: error occurred at recursive SQL level 1
ORA-00900: invalid SQL statement
Since my Stored Procedure was compiled w/o error, and returns data from local call, I will expected there is no error in it. But I'm not 100% sure, here's my Stored Procedure :
CREATE OR REPLACE procedure my_schema.SP_READ_MEMBER(keywordP in varchar2, birthdayP in varchar2, resultP out sys_refcursor)
is
v_prg_name varchar2(20) := 'SP_READ_MEMBER';
sys_sql varchar2(1000);
begin
Insertlog(SYSDATE, v_prg_name, '1.0 Start');
sys_sql := sys_sql || 'select a.no, a.name, a.id_no, to_char(a.birthday, ''yyyy/MM/dd'') as birthday, ''REAL member'' as mtype, email, mobile from members a where 1=1 ';
if keywordP is not null then
sys_sql := sys_sql || ' and (a.no=''' || keywordP || ''' or a.name=''' || keywordP || ''' or a.id_no=''' || keywordP || ''') ';
end if;
if birthdayP is not null then
sys_sql := sys_sql || ' and a.birthday=to_date(''' || birthdayP || ''', ''yyyy/MM/dd'') ';
end if;
open resultP for sys_sql;
Insertlog(SYSDATE, v_prg_name, '2.0 Finished w/o error');
exception
when others then
declare
error_time VARCHAR2(30) := RTRIM(TO_CHAR(SYSDATE, 'YYYY/MM/DD, HH24:MI:SS'));
error_code NUMBER := SQLCODE;
error_msg VARCHAR2(300) := SQLERRM;
begin
rollback;
DBMS_OUTPUT.PUT_LINE(error_time || ',' || TO_CHAR(error_code) || ',' || error_msg);
Insertlog(SYSDATE, v_prg_name, error_msg || ', 3.0 ERROR, sql:' || sys_sql);
end;
end SP_READ_REP;
/
How do I fix this problem ?
Any suggestions are welcome~
You hit a restriction. Cursor variable declaration says:
Using a cursor variable in a server-to-server remote procedure call (RPC) causes an error. However, you can use a cursor variable in a server-to-server RPC if the remote database is a non-Oracle database accessed through a Procedural Gateway.
Workaround might be to move the procedure into your local database and fetch data over the database link.

How to send email from oracle plsql through third party hosting mail server

Deal all,
I want to send an email notification directly form Oracle plsql using outer mail server (External hosting), I've searched on the internet and found a useful way to send an email using Oracle UTL_smtp package, but it requires to have the mail server locally not remotely.
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) := 'Oracle9.2';
mailhost VARCHAR2(30) := '127.0.0.1'; -- local database host
BEGIN
c := utl_smtp.open_connection(mailhost, 25); -- SMTP on port 25
utl_smtp.helo(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;
So, how can this be done using external domain!!
Please help..

Emails sent through Oracle losing dots(.)

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;

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