Labels

2017 absence absence management Account accounting Agents AIM aliases AME and APEX API application application utilities lookups approval assignments ATO Australia Automation Bank bi publisher budget business business groups Business Objects CAGR candidates cartisian product case CEMLI Center Stage channels Classification Cloud competency concurrent Configuration configuration profile constants contextualization conversion correction cost costing count coverage area customization data database date DateTracked deductions define design develop DFF diagnostics distinct document earnings ebs EIT Element employee enhancements erp excel expression extension failure Fastformula FBT Flexfield FND fndload foreign key forms Formula fringe benefit FRM-40654 from FTE Functions fund fusion GenAI GL global transfer grade help hierarchy HR HRMS human resource management system implementation income information interfaces internet interview job join key flexfield KFF KPI language learning leave legal employer legislation links listagg lists localization location management New Year OAIAS obia obiee OLF onboarding oracle Oracle ACE Oracle AI Agent Studio oracle applications oracle descriptive flex field oracle descriptive flexfield oracle ebs oracle erp oracle fusion HCM Oracle HCM oracle hrms oracle hrms interview questions oracle hrms modules oracle hrms modules list oracle hrms organization oracle hrms table oracle hrms tables oracle hrms tutorial oracle irecruitment oracle legal entities oracle lookups oracle organization hierarchy oracle payroll oracle payroll interview questions oracle payroll tables oracle self service order by Organization organization type otbi package package body package specification patch payg Payment payroll people group perform person personalisation phase pl/sql position Power BI primary key process profile programs project Python qualifier Query question questions Recruiting Center Recruitment regex regular expression reporting tool reports requests requirement requisition resume retropay RICE salary schema security profile select SIT smartorg sql statutory stores STP Super Superannuation system systems Table Taleo taleo 15B Taleo Recruitment tax TCC termination test testing trunc update user group user management user type value set variables View Views Web ADI webadi where work relationship

Sunday, 31 May 2026

From Oracle to Outlook - automating SQL query output using Python - Part II

Ok, here is the second and final part of this topic. So lets resume from where we left off

Now that the building blocks are clear, let’s walk through what actually happens when you run the script



The script starts by calling setup_logging(), which ensures the log directory exists and configures a file + console logger. The log file name includes a timestamp, so each run has its own log.

Next, load_db_credentials() reads db_credentials.txt, parses the key/value pairs, and constructs a DbCredentials object. 

If the file is missing or any required key is missing, the script raises an error early, before trying to connect.

get_db_connection(credentials) then calls
 cx_Oracle.connect(credentials.username, credentials.password, credentials.dsn) and logs that the connection is being established. 

From this point on, the script can run any SQL that your Oracle user is authorised to run.

====




build_query_definitions() produces the ordered list of QueryDefinition objects that will represent each section in the outlok mail body. A simple loop iterates over this list, and for each definition:

  • run_query(connection, query_def) executes query_def.sql using pandas.read_sql().
  • The resulting DataFrame has NaN values replaced with empty strings via fillna("").
  • The index is reset so that row numbering in the HTML starts from 1, which makes it easier for business users to reference specific rows in emails or follow up calls.


====



dataframe_to_pretty_html(df) is responsible for turning the DataFrame into HTML and applying some basic styling. 

The script defines constants such as TABLE_FONT_SIZE, TABLE_HEADER_BG, TABLE_EVEN_ROW_BG, and TABLE_BORDER to keep the look consistent across all sections. 

This gives the user a readable, Outlook friendly table without needing a full templating engine.

====


For each query, the script builds an HTML block that looks roughly like:

  • Section heading (query_def.name)
  • Short description (query_def.description)
  • Either a styled HTML table or the empty_message
  • Some spacing between sections (via a SECTION_GAP constant)

Before the sections, the script adds a standard intro paragraph stored in EMAIL_INTRO_TEXT, which explains that the email shows “the latest query extracts for review”, highlights that it is a snapshot for “yesterday”, and that the message has been created as an Outlook draft for manual review and sending. 

This text is easy to adjust for different business audiences or different frequency (e.g. weekly or monthly snapshots).

All of these pieces are concatenated into a single HTML string that becomes the body of the email. Because the output is pure HTML, you can further tune it with headings, colours, or additional notes without touching the database logic.

===============

If you would like to get the full code. Please leave your email address in the comment section and I'll share it




No comments:

Post a Comment