New to Kestra?
Use blueprints to kickstart your first workflows.
Schedule a UTC-anchored, backfillable Oracle SQL report with Kestra, convert it to CSV, and email it as an attachment, skipping empty days and alerting Slack on failure.
Turn a daily Oracle Database query into an automated email report without writing glue code or babysitting a cron job. This blueprint runs an aggregate SQL query against Oracle on a schedule, anchors the reporting window to UTC so the numbers are correct regardless of the database server clock, converts the result to CSV, and emails it to your stakeholders as an attachment. It skips the send entirely when a day has no data and posts a Slack alert if anything fails, so a missed morning report is never silent. It also stays fully backfillable: re-run any past day on demand without editing the flow.
io.kestra.plugin.core.trigger.Schedule trigger fires every morning at 06:00 UTC (cron: 0 6 * * *).daily_sales_report task (io.kestra.plugin.jdbc.oracle.Query) aggregates the report day's orders by region and stores the full result set in internal storage (fetchType: STORE). The day is passed as a bound :day parameter and the window is built with FROM_TZ(... 'UTC'), not the server clock.email_when_data task (io.kestra.plugin.core.flow.If) checks outputs.daily_sales_report.size > 0.report_to_csv (io.kestra.plugin.serdes.csv.IonToCsv) converts the stored ION result to CSV and email_report (io.kestra.plugin.email.MailSend) emails it over SMTP with TLS as an attachment.log_no_data (io.kestra.plugin.core.log.Log) records that the day was empty instead of sending an empty attachment.errors block sends a io.kestra.plugin.slack.notifications.SlackIncomingWebhook alert with the execution id.The report day is derived from inputs.report_date (else the trigger or execution date minus one day) and rendered once into vars.report_day, which drives the SQL window, the email subject, and the log line in lockstep.
report_date set, no code changes.Oracle's own scheduler (DBMS_SCHEDULER) can run SQL on a timer, but it cannot convert results to CSV, send authenticated SMTP email with attachments, branch on whether the result was empty, or alert Slack when the job fails. Kestra ties all of that together in one declarative YAML flow: an event or time trigger starts the run, retry blocks ride out transient Oracle and SMTP blips, the errors block guarantees failures surface, and every execution is captured with full logs and lineage you can replay. Because the date is parameterized, the same flow that runs nightly also backfills history.
jdbc:oracle:thin:@//host:1521/service.orders table (with created_at stored in or comparable against UTC) and a customers table to join and aggregate.Set these as Kestra secrets, never inline:
ORACLE_USERNAME: the Oracle database user that runs the report query.ORACLE_PASSWORD: the password for that Oracle database user.SMTP_HOST: the hostname of the SMTP server used to send the report.SMTP_USERNAME: the username used to authenticate to the SMTP server.SMTP_PASSWORD: the password used to authenticate to the SMTP server.REPORT_RECIPIENTS: recipient email address(es) for the report.SLACK_WEBHOOK: the Slack Incoming Webhook URL the failure alert is posted to.ORACLE_USERNAME, ORACLE_PASSWORD, SMTP_HOST, SMTP_USERNAME, SMTP_PASSWORD, REPORT_RECIPIENTS, and SLACK_WEBHOOK secrets.oracle_url variable and, if needed, the from_address input default to match your environment.created_at is stored in or comparable against UTC.report_date set.