Sending email based on field name UTL_MAIL.send - oracle

How can I send an email based on what is entered into a apex Text field. eg If I enter me#test.com in :p6_supervisor, I would like the email to be sent to that person.
At present I have a preset UTL_MAIL.send which is working.
begin
UTL_MAIL.send(sender => 'test#test.com',
recipients => 'test1#test.com',
subject => 'Test,
message => 'Please Note this is a test' );
end;
But of course its for another purpose, which is sending email to one recipient from a trigger.
Below is the Cursor example
create or replace function "email"
( name_in IN varchar2 )
RETURN number
IS
supervisoremail varchar2(30);
CURSOR c1
IS
select
supervisoremail
from
EMPLOYEE,supervisors
where TO_DATE(contract_start_period,'DD-MM-YYYY') < TO_DATE (SYSDATE,'DD-MM-YYYY') - 275
and (supervisors.supervisorname = employee.supervisorname1
or supervisors.supervisorname = employee.supervisorname2)
and employee_name ='test'
;
BEGIN
OPEN c1;
FETCH c1 INTO supervisoremail;
CLOSE c1;
RETURN supervisoremail;
END;

It'll work, no problem. A simple way is to
create a text item (P6_SUPERVISOR)
create a button which submits the page; you need it so that P6_SUPERVISOR's value is set into the session state
create a process which calls UTL_MAIL; P6_SUPERVISOR item's contents is used as a source for the RECIPIENTS parameter. For example:
UTL_MAIL.send (sender => 'test#test.com',
recipients => :P6_SUPERVISOR,
subject => 'Test message - subject',
MESSAGE => 'Test message - message body');
[EDIT: how to send mails in a loop?]
I'm not sure what you meant by creating a function; it returns just one e-mail address that, probably, belongs to name passed through the NAME_IN parameter (but you used the 'test' name in cursor query).
However, you specified that the function returns a NUMBER, while variable you're selecting the result into is a VARCHAR2. So, which one of these is true?
If you insist on a function, don't enclose its name into double quotes as you'll always have to reference it that way (double quotes, correct upper/lower/mixed case).
Furthermore, what is contract_start_period column's datatype? If it is DATE, don't TO_DATE it. The same goes for SYSDATE - it is a function that returns DATE datatype anyway, so it is wrong to convert it to date once again.
Here's an example which uses a cursor FOR loop (as it is easier to maintain) and sends mail to all supervisoremail addresses returned by that SELECT statement.
begin
for cur_r in (select supervisoremail
from employee e join supervisors s on s.supervisorname = e.supervisorname1
or s.supervisorname = e.supervisorname2
where contract_start_period < sysdate - 275
and e.employee_name = 'test'
)
loop
utl_mail.send(sender => 'test#test.com',
recipients => cur_r.supervisoremail,
subject => 'Test message - subject',
message => 'Test message - message body');
end loop;
end;

Related

Validate email that was sent using apex_mail.send and apex_mail_log

I'm using Oracle Apex version 22.2. I have a pl/sql process where I'm sending an email, and another process runs based on the status of that email being sent. I can select the mail_id from apex_mail_log and display it on one of my page items just fine. But when I try to use that mail_id to select the mail_send_error of that email record, I keep getting ORA-01403: no data found (the email sends regardless of this error). I have validated that it's returning the correct mail_id of the record that was just inserted. I have also validated that my select statement runs just find when ran in SQL Workshop. I need to be able to validate this email was actually sent before I can continue with the other processes, any ideas?
declare
v_orgname varchar2(500);
v_mailid number;
v_mailresult number;
begin
-- select our variables to send with our email
select name into v_orgname from organizations where keyid = :P277_ORGKEYID;
v_mailid := apex_mail.send (
p_to => :P277_EMAILTO,
p_from => :P277_EMAILFROM,
p_template_static_id => 'ACTUM_WELCOME_LETTER',
p_placeholders => '{' ||
' "SITENAME":' || apex_json.stringify( v_orgname ) ||
' ,"MY_APPLICATION_LINK":' || apex_json.stringify( apex_mail.get_instance_url || apex_page.get_url( 'test' )) ||
' ,"SUBID":' || apex_json.stringify( :P277_PARENTID ) ||
'}' );
apex_mail.push_queue();
-- Using the mailid, we can select the result of that email
select nvl(mail_send_error,0) into v_mailresult from apex_mail_log where mail_id = v_mailid;
-- This page item is being set so this variable is correct, why is my process saying no data found?
select v_mailid into :P277_MAILID from dual;
-- If the result is a success, we select 1 into our mail sent variable to tell the login process to run
if v_mailresult = 0 then
select 1 into :P277_EMAILSENT from dual;
else
select 0 into :P277_EMAILSENT from dual;
end if;
end;
The issue is that the apex_mail.push_queue is an asynchronous call. Your code to be executed afterwards does not wait for the actual mail sending to finish. You can check this in DBA_SYNONYMS where APEX_MAIL synonym leads to APEX_220200.WWV_FLOW_MAIL_API. Unwrap its code and see that it leads to WWW_FLOW_MAIL.PUSH_QUEUE which leads to PUSH_QUEUE_BACKGROUND whose code is:
SYS.DBMS_SCHEDULER.RUN_JOB( JOB_NAME => 'ORACLE_APEX_MAIL_QUEUE', USE_CURRENT_SESSION => FALSE );
So, what you can do, you can run directly that job but with USE_CURRENT_SESSION => TRUE, if you really want to synchronously wait for the execution result. An other option is to check the result in a separate block of code / functionality, and then take UI rendering decisions based on that result.

Oracle procedure for send single email from query result

My Oracle procedures are not working as expected, kindly advise which part needs to update.
Expectation: The query result will send in single emails.
For example, the result from the query has 3 entries.
However, the email sending with 3 separate emails instead of 1 email content of 3 entries.
v_subject := 'Missing info';
for email in
(
select *
from Info WHERE info_status is null
)
loop
v_message := 'Name' || email.name || ' --> '|| email.status || ' '|| email.year || ' ';
SEND_MAIL(
SENDER => v_From,
RECIPIENT => v_TO,
SUBJECT => v_subject,
MESSAGE => v_message);
END LOOP email;
As written, the code inside the loop runs once for each row returned from the query.
Hint: Build the MESSAGE and RECIPIENT values for each row returned, then send only one e-mail at the end.

How can i get current username in PL/SQL?

i have some code
create or replace function policy_test (p_schema varchar2, p_object varchar2)
return varchar2 is
v VARCHAR2(30);
begin
v := USER;
return 'name = ' || v;
end;
Begin
DBMS_RLS.add_policy (
object_schema => 'system',
object_name => 'WORKMAN',
policy_name => 'WORKMAN_policy_test2',
function_schema => 'system',
policy_function => 'policy_test',
statement_types => 'select',
update_check => true
);
End;
and i'd like to ruturn 'name=system' or 'name=Jack' from function policy_test, but i get some error :
[28113] ORA-28113 policy predicate has error
How can i get current user name in policy_test and return sting like 'name=Jack' ?
Your particular VPD policy will append the return value to an implicit WHERE clause. The problem lies in your desired behavior. You stated, "and i'd like to return 'name=system' or 'name=Jack' from function policy_test"
If you were to write out an SQL statement like this: SELECT * FROM mytable WHERE name=system or SELECT * FROM mytable WHERE name=Jack, what would happen? The query will fail every time. When doing string comparison in a WHERE clause, you must enclose the string literal with single tick marks. Change it to WHERE name = 'Jack' and you have valid SQL.
Back to your function. Your function is returning a string, name=Jack and so WHERE name=Jack is what Oracle is generating. You haven't quoted the string literal so the SQL fails. The nature of VPD hides the exception raised (very frustrating) but Oracle does log it in the trace file.

Oracle PL/SQL. Pass mail address loop output to oracle email procedure

I have a procedure that sends mail. I want to send a mail by selecting the email addresses from a view and pass the addresses to my mail procedure.
This code works in that it outputs multiple email addresses and incident numbers from my database.
create or replace procedure SEND_REMINDER_MAIL as
CURSOR c1 IS
SELECT contact_email
FROM TEST.incidents_view
WHERE updated <= current_timestamp - interval '1' minute
and status_code = '100';
cursor c2 is
SELECT incident_number
FROM TEST.incidents_view WHERE updated <= current_timestamp - interval '1' minute
and status_code = '100';
v_contact_email varchar2(300);
v_incno VARCHAR2(10);
BEGIN
-- Open the cursor and loop through the records
OPEN c1;
FETCH c1 INTO v_contact_email;
EXIT WHEN c1%NOTFOUND;
-- Print values
dbms_output.put_line(v_contact_email);
end loop;
CLOSE c1;
open c2;
LOOP
fetch c2 into v_incno;
EXIT WHEN c2%NOTFOUND;
dbms_output.put_line(v_incno);
end loop;
CLOSE c2;
end;
/
What I need to do though, is pass just the email addresses into the existing email procedure to fire off emails to anyone who comes up on the list generated by the output.
This is the next part of the procedure, I have used dbms_output to test and verify that the email addresses are being generated correctly and passed into v_contact_email. Now, when I try and send the mail, only one address gets passed in by this:
send_mail.send(
ToList=> v_contact_email,
Subject=> 'Ticket closing warning.',
Body=> 'Please note, your ticket '|| v_incno ||' will be subject to automatic closure',
FromEmail=> 'donotreply#test.com.au',
FromHost=> 'emailsrv',
SMTPServer=> 'emailsrv',);
close c1;
close c2;
End;
/
It's not sending to the several emails that are shown to be correctly passed into v_contact_email. It just sends one email out and nothing else.
Why won't the several email addresses that are looped into v_contact_email result in several emails going out, instead of just one?
How can I fix it so the:
send_mail.send(
ToList=> v_contact_email,
Subject=> 'Ticket closing warning.',
Body=> 'Please note, your ticket '|| v_incno ||' will be subject to automatic closure',
FromEmail=> 'donotreply#test.com.au',
FromHost=> 'emailsrv',
SMTPServer=> 'emailsrv',);
close c1;
close c2;
End;
/
Part of the code correctly loops through the full result set? Instead of just getting one address and firing off one email before doing nothing else?
The first code you posted isn't entirely valid; it the first cursor lacks LOOP. If you fix that, the result will be:
bunch of e-mail addresses
bunch of incident numbers
The first loop fetches e-mail addresses, so v_contact_email contains only the last address fetched. The same goes for incident numbers.
One option is that you'd want to nest those loops, something like this (I'm using cursor FOR loops as they are easier to maintain that explicitly declared cursors, which you have to declare (as well as cursor variable(s), open, loop, take care about exiting the loop, close the cursor) - if you use cursor FOR loop, Oracle does most of those things for you.
begin
for cur_r in (select contact_email from incidents_view where ...) loop
for cur_i in (select incident_number from incidents_view where ...) loop
send_mail.send(ToList => cur_r.contact_email,
Subject => 'Ticket closing warning.',
Body => 'Please note, your ticket '|| cur_i.incident_number ...
);
end loop;
end loop;
end;
But, why do you have two cursors? They look the same (except of what they select), but - FROM clauses are equal, WHERE clauses are equal ... why not using only one cursor? E.g.
begin
for cur_r in (select contact_email, incident_number
from incidents_view where ...
) loop
send_mail.send(ToList => cur_r.contact_email,
Subject => 'Ticket closing warning.',
Body => 'Please note, your ticket '|| cur_r.incident_number ...
);
end loop;
end;
After your help Littlefoot, this is what I came up with which did exactly what I wanted.
create or replace procedure SEND_MAIL_REMINDER as
begin
for cur_r in (SELECT customer_email, incident_number
FROM incidents_view
WHERE updated <= current_timestamp - interval '24' hour
and status = '20') loop
send_mail.send(
ToList=> cur_r.customer_email,
Subject=> 'Ticket Closure Warning.',
Body=> 'Please note, your ticket '|| cur_r.incident_number ||' has been in status 20 for some time.',
FromEmail=> 'donotreply#blah.com',
FromHost=> 'mailsrv',
SMTPServer=> 'mailsrv',
AttachList=> '',
Directory=> '');
end loop;
end;
/

Oracle Apex error handling

I have a textbox (tb_pcode) that user must enter the personnel code. This is a part of my code :
declare
n varchar2(20);
begin
select name into n
from pers e
where e.pcode = :tb_pcode;
exception
when no_data_found then
apex_error.add_error (
p_message => 'No person found!',
p_display_location => apex_error.c_inline_in_notification );
end;
but this lines ignore at all and no message display.
apex_error.add_error (
p_message => 'No person found!',
p_display_location => apex_error.c_inline_in_notification );
Why?!
I've just tried it on Apex 5.1.1, works just fine.
Where did you put that code? I created a validation on the TB_PCODE text item; validation type is "PL/SQL Function (returning Error Text)".
On the other hand, one reason might be that you, actually, entered a valid code and query returned something (i.e. SELECT didn't raise no-data-found).

Resources