Building Dynamic Email Templates with Attachments in Oracle APEX Using APEX_MAIL: A Step-by-Step Guide


🔹 Introduction

In this blog, we will build a dynamic Purchase Order Email Notification system using Oracle APEX Email Templates.
You’ll learn how to create reusable templates, use conditional logic, and send emails using PL/SQL. 

📌 PART 1 - Create Email Template

Step 1: Navigate to Email Templates

Go to:
App Builder → Your Application → Shared Components → Email Templates → Create

Step 2: Enter Template Details

Fill the following:

  • Template Name → PO Approvals
  • Static Identifier → PO_APPROVALS
  • From Name → ERP System
  • From Email → noreply@yourcompany.com
  • Subject → PO #PO_NUMBER# - #SUBJECT#

👉 Use placeholders like #PO_NUMBER# to inject dynamic values.

Step 3: Add Header Content

<p><strong>Hello from Our ERP System</strong></p>
<hr/>

Step 4: Add Body Content

  • Include placeholders (#APPROVER_NAME#, #PO_STATUS#)
  • Add HTML table for PO details
  • Use directives:
    • {if/} → Conditional display
    • {case/} → Status-based logic

👉 Example use cases:

  • Show warning only for high value
  • Show different messages for Approved / Rejected
Code in Body:

<p>Dear <strong>#APPROVER_NAME#</strong>,</p> <p>The following Purchase Order requires your attention:</p> <!-- PO Details Table --> <table style="width:100%; border-collapse:collapse; font-size:14px; margin:15px 0;"> <thead> <tr> <th style="background-color:#4472C4; color:white; padding:10px; border:1px solid #ccc; text-align:left;">PO Number</th> <th style="background-color:#4472C4; color:white; padding:10px; border:1px solid #ccc; text-align:left;">Supplier Name</th> <th style="background-color:#4472C4; color:white; padding:10px; border:1px solid #ccc; text-align:left;">Amount</th> <th style="background-color:#4472C4; color:white; padding:10px; border:1px solid #ccc; text-align:left;">Status</th> <th style="background-color:#4472C4; color:white; padding:10px; border:1px solid #ccc; text-align:left;">Approver</th> </tr> </thead> <tbody> <tr> <td style="padding:10px; border:1px solid #ccc; background:#f9f9f9;">#PO_NUMBER#</td> <td style="padding:10px; border:1px solid #ccc; background:#f9f9f9;">#SUPPLIER_NAME#</td> <td style="padding:10px; border:1px solid #ccc; background:#f9f9f9;">#PO_AMOUNT#</td> <td style="padding:10px; border:1px solid #ccc; background:#f9f9f9;"><strong>#PO_STATUS#</strong></td> <td style="padding:10px; border:1px solid #ccc; background:#f9f9f9;">#APPROVER_NAME#</td> </tr> </tbody> </table> <!-- High Value Warning --> {if HIGH_VALUE_MESSAGE/} <p style="color:orange; font-weight:bold; background:#fff3cd; padding:10px; border-left:4px solid orange; margin:10px 0;"> ⚠️ #HIGH_VALUE_MESSAGE# </p> {endif/} <!-- Status Block --> {case PO_STATUS/} {when APPROVED/} <p style="color:green; font-size:18px; font-weight:bold;"> ✅ This PO has been APPROVED </p> {when REJECTED/} <p style="color:red; font-size:18px; font-weight:bold;"> ❌ This PO has been REJECTED </p> {otherwise/} <p style="color:gray;"> 🕐 Status: <strong>#PO_STATUS#</strong> </p> {endcase/} <p>Regards,<br/><strong>ERP System</strong></p>

Step 5: Add Footer

<hr/> <p style="font-size:12px; color:gray;"> This is an automated message. Please do not reply. </p>

Step 6: Add Plain Text Version

Provide fallback content for non-HTML emails.

Step 7: Add Custom CSS

  • Go to Advanced → Load Default HTML
  • Add styles for:
    • Status colors (green/red)
    • Warning messages
    • Table formatting
Code in HTML Template under Advanced:

Replace below style code.

<style> .po-high-value { font-size: 1.25em; color: orange; font-weight: bold; background-color: #fff3cd; padding: 8px; } .po-approved { font-size: 1.5em; color: green; font-weight: bold; } .po-rejected { font-size: 1.5em; color: red; font-weight: bold; } .my-table { width: 100%; border-collapse: collapse; font-size: smaller; } .my-table th { background-color: #d3d3d3; text-align: left; padding: 5px; border: 1px solid #000; } .my-table td { padding: 5px; border: 1px solid #000; } </style>



📌 PART 2 - Page Designer Setup

Step 8: Create Region

  • Create Static Content Region
  • Title: Purchase Order Details

Step 9: Create Page Items

Create these fields:

  • PO Number
  • PO Status (Select List: APPROVED / REJECTED / PENDING)
  • Approver Name
  • Supplier Name
  • PO Amount
  • High Value Message

👉 Tip: Use correct page prefix (P2_, P3_, etc.)

Step 10: Create Button

  • Button Name → SEND_EMAIL
  • Action → Submit Page
  • Style → Hot

📎PART 3 - Adding File Attachment to Email in Oracle APEX

🔹 Step 11: Create File Upload Item

In your page (same region), create a new item:

  • Item NameP2_ATTACHMENT
  • Type → File Upload
  • Label → Attach Document

Key Settings:

  • Storage Type → Table APEX_APPLICATION_TEMP_FILES
  • Purge File at → End of Request
  • Display As → Inline File Browse
  • Allow Multiple Files → No (or Yes based on need)

👉 This allows users to upload a file before sending email.


📌 PART 4 - Create PL/SQL Process

Step 12: Go to Processing Tab

Step 13: Create Process

  • Name → Send PO Approval Email
  • Type → PL/SQL Code

Step 14: Add PL/SQL Code

Use apex_mail.send with:

  • Template Static ID
  • JSON placeholders
  • Dynamic page item values

👉 Key concepts:

  • apex_json.stringify() for safe values
  • Conditional placeholder for optional fields
Code:

DECLARE -- Variables to hold the uploaded file details l_file_name VARCHAR2(255); l_mime_type VARCHAR2(255); l_file_content BLOB; l_mail_id NUMBER; BEGIN -- ───────────────────────────────────────────── -- STEP A: Send the email (same as before) -- ───────────────────────────────────────────── l_mail_id := apex_mail.send ( p_to => 'your_mail@gmail.com', p_template_static_id => 'PO_APPROVALS', p_application_id => :APP_ID, p_placeholders => '{' || ' "PO_NUMBER":' || apex_json.stringify(:P2_PO_NUMBER) || ',"PO_STATUS":' || apex_json.stringify(:P2_PO_STATUS) || ',"SUBJECT":' || apex_json.stringify('PO Notification') || ',"APPROVER_NAME":' || apex_json.stringify(:P2_APPROVER_NAME) || ',"SUPPLIER_NAME":' || apex_json.stringify(:P2_SUPPLIER_NAME) || ',"PO_AMOUNT":' || apex_json.stringify(:P2_PO_AMOUNT) || CASE WHEN :P2_HIGH_VALUE_MSG IS NOT NULL THEN ',"HIGH_VALUE_MESSAGE":' || apex_json.stringify(:P2_HIGH_VALUE_MSG) ELSE '' END || '}' ); -- ───────────────────────────────────────────── -- STEP B: Add attachment only if file uploaded -- ───────────────────────────────────────────── IF :P2_ATTACHMENT IS NOT NULL THEN -- Read the uploaded file from APEX temp table SELECT filename, mime_type, blob_content INTO l_file_name, l_mime_type, l_file_content FROM apex_application_temp_files WHERE name = :P2_ATTACHMENT; -- Attach the file to the email we just sent apex_mail.add_attachment ( p_mail_id => l_mail_id, -- Links to the email above p_attachment => l_file_content, p_filename => l_file_name, p_mime_type => l_mime_type ); END IF; -- ───────────────────────────────────────────── -- STEP C: Push the queue to actually send -- ───────────────────────────────────────────── apex_mail.push_queue; END;

Step 15: Add Button Condition

Set:

  • When Button PressedSEND_EMAIL

Step 16: Success Message

Email sent successfully!

Step 17: Save Application

Save and run the application, enter the required details in the PO form, then click the Send Email Notification button
and verify the email in your inbox.

Final form Output:


Mail Box Output:



Another PO number Mail Box Output:


📌 PART 4 - Testing Scenarios

✅ Scenario 1: Approved + High Value

  • Shows:
    • Table
    • Warning message
    • Green Approved status

❌ Scenario 2: Rejected

  • Shows:
    • Table
    • No warning
    • Red Rejected message

⏳ Scenario 3: Pending

  • Shows:
    • Table
    • Neutral status message

🎯 Conclusion

Using Oracle APEX Email Templates, you can build dynamic, reusable, and professional email systems

with minimal effort. This approach improves maintainability and enables advanced features like conditional

rendering and styling.

🚀 Future Enhancements

  • Multi-recipient email support
  • Approval workflow integration
  • Email tracking & logging

Comments

Popular posts from this blog

Building Secure RESTful Services in Oracle APEX 24.2 Using ORDS, OAuth2 Client Credentials, and PL/SQL

Building a Portfolio Generator in Oracle APEX: A Step-by-Step Guide to Generate Downloadable Portfolio Documents

Implementing WhatsApp OTP Verification in Oracle APEX Using UltraMsg API