Dyn Email Delivery (and the Dyn business) are reaching end-of-life after May 31, 2023. Use this guide to get acquainted with and migrate to its replacement, the Email Delivery service of Oracle Cloud Infrastructure (OCI).
OCI Email has most of the features of Dyn Email, but there are a few key ones in final development and nearing release in the coming weeks. In addition to reputable email delivery, OCI currently offers other core features such as bounce and complaint collection, email authentication standards, approved (wildcard) domains, deliverability performance including possible dedicated IP resources, detailed and summary activity reporting, and a host of other features offered through tight integration with other Oracle Cloud services.
As of this writing, we are working on features such as open and click engagement tracking, HTTPS API sending, custom headers, and custom return path among others. Some of these features have already reached limited availability state; please reach out to us if you need these features or wish to gain early access.
For more information on availability and timeline, or to gain early access when available, please reach out to migrations@dyn.com.
Depending on your use cases and level of integration, there may be a lot of pieces to consider. If you have questions about a certain feature or need guidance on how to map your current Dyn Email integration over to Oracle Cloud, please reach out to us. While we cannot migrate certain data over (SMTP and web portal passwords, user permissions, and others), we do have tools and guidance we can provide for migration of approved senders and/or suppression lists (see below). Reach out to migrations@dyn.com for help.
Approved Sender / Email Domain Migration Tool
The OCI Email Delivery service team can provide a relatively simple Python script which reads your approved senders in Dyn Email Delivery and create the matching email domains and approved senders in Oracle Cloud. Contact us for more information.
Important Note on Suppression List Migration
Suppression lists exist to help maintain good email sender reputation by preventing invalid or unwilling email addresses from being repeatedly emailed. Both Dyn and Oracle Cloud charge for emails submitted to recipients that are suppressed, even though the emails are not sent. For this reason especially, and to keep a focus on good sender reputation, we highly recommend good email and suppression list hygiene; that is:
This way, you save on costs associated with submitting email for suppressed recipients, and your email sends are more optimized and targeted only to recipients who exist and want emails.
You can safely skip migrating suppression lists if you've been practicing at least steps 1 + 2 above; that is, updating your own email lists to reflect updates to the suppression list. Otherwise, we strongly recommend reviewing your current Dyn suppression list(s) to make sure the addresses there are updated/removed in your own lists; only then would it be ok to skip suppression list migration. For those who must migrate their suppression list, the migration tool mentioned above can do this; but again, this is not ideal from the perspective of cost and list hygiene.
We recommend the following steps to get up and running toward your first email send.
Key documentation links for reference:
Create an Oracle Cloud Infrastructure (OCI) account
Oracle Cloud Infrastructure requires an account (“tenancy”) be created to support setting up cloud services such as Email Delivery. In addition, because OCI utilizes a different means for authenticating web and SMTP users, these accounts must be configured fresh there. Existing Dyn credentials cannot be transferred from Dyn to OCI.
If you do not yet have an account, you can start with a free account. Oracle Cloud’s Free Tier includes a practical amount of infrastructure and services to get started, including allotment to send up to 100 emails a day to test out the service. You will have to enter a credit card, but it is not billed.
Before setting up Email Delivery, consider how best to logically separate your email configuration and activity, if needed. Dyn Email Delivery uses sub-accounts to segment email sending and reporting, and helps in controlling access. OCI uses “compartments” to do this, allowing you to organize and isolate your cloud resources such as approved senders. For more information and to create Oracle Cloud Infrastructure compartments, see Managing Compartments.
Set up Users and Groups
Unlike Dyn Email Delivery, Oracle Cloud Infrastructure provides a robust set of permission features that allow you to set up granular permission policies to manage access to various elements of the Email Delivery service, including sending and approved sender creation permissions. For more information, see Overview of Oracle Cloud Infrastructure Identity and Access Management. This includes the recommended use of Groups to help organize with similar access, and grant them appropriate access to manage resources.
Once you have your tenancy created, you have the option to set things up manually using the OCI web console, or you can look at scripts provided here to utilize Oracle Resource Manager and the Terraform CLI to automate setup and management.
Generate SMTP Credentials
SMTP credentials are added to a User within your tenancy for use in submitting emails to OCI for delivery. Like Dyn, credentials used to authenticate into the OCI web console are different than those used for email submission.
If you wish, you can disable capabilities for the user(s) with SMTP credentials for security purposes. Click the Edit User Capabilities button on user details page.
Oracle Cloud offers a robust set of services and security control options to support even the most complex requirements. However, you can get started for reputable sending relatively quickly.
Below, we offer condensed steps for a minimal setup in OCI Email Delivery. You can also consult the Getting Started with Email Delivery guide for more detail.
A word about regions: Oracle Cloud is a region-based service, unlike Dyn Email Delivery which has a single set of global endpoints. You will want to consider which region(s) of Oracle Cloud to set up in, as each region requires its own setup. For now, you can just pick the region closest to where you are to get started.
The ideal way to think about this: where do your users reside in the world and are there restrictions within those countries as relates to where email comes from? If you have an Australian-based arm of your company, you could set up a region there and another one for U.S-based affairs, etc.
Minimum Requirements for OCI Email Delivery Configuration
Add IAM Service Policy to Allow Email Delivery Configuration
OCI uses Identity and Access Management (IAM) policies to help control access to cloud resource management. Email Delivery offers a single policy or more granular policies, depending on your needs. To enable all operations on all email resources for a specific user group, use the following policy:
Allow group [Your Group Name] to manage email-family in tenancy
There are other policies you will want in place, especially when accessing logs and managing suppressions. See Creating User Permissions in the OCI Email Delivery documentation for more detail.
Before migrating approved senders, we recommend assessing what you have set up in Dyn. If you have inactive or abandoned approved senders, we recommend cleaning these or at least not bringing them over to OCI. If you used an approved sender address five years ago, but no longer need it, you would not need to include that for OCI.
Reporting data will remain in Dyn Email and cannot be migrated. Dyn Email will remain available beyond the end-of-life date for a short time, only to allow for report retrieval.
Add Email Sending Domain(s)
OCI uses Email Domains to centralize configuration and reporting and make it easier to set up important, industry-standard authentication measures like SPF and DKIM. For more information, see Managing Email Domains.
For each of the domains you will send email from:
If you have a lot of approved senders and/or sending domains, we can provide a Python script which copies your approved senders over and creates all the respective email domains. Please reach out to migrations@dyn.com for this option.
Set up DKIM for your Email Domain(s)
DKIM (DomainKeys Identified Mail) is an important step to ensure email you send reaches the inbox and is considered reputable. It utilizes DNS records to help achieve cryptographic signing of emails, ensuring the email is seen by inbox providers as genuine.
We highly recommend setting up DKIM fresh with new signing keys especially if you are currently using less secure 1024-bit or less encryption strength; OCI Email Delivery defaults to using strong, 2048-bit encryption. OCI also encourages the use of CNAME records for setting up DKIM (in contrast to the TXT record method used in Dyn), which allows for easier, seamless key rotation.
To set up fresh DKIM manually, see the guide to Setting up an Email Domain with DKIM for helpful steps, including links to documentation for several popular DNS providers. While you can attempt to send some test mail without DKIM set up, we highly recommend setting up DKIM right away to avoid delivery issues later. In addition, certain features require DKIM be set up as well (such as wildcard approved senders and custom headers).
Configure SPF
SPF (Sender Policy Framework) is an important, industry-standard measure to let email inbox providers know that OCI Email Delivery is allowed to deliver emails on your behalf. Like DKIM, SPF uses DNS records. See the Configuring SPF guide for steps to set up this important permission. Note that SPF is set up by region, so you would want to use the includes for the specific region(s) you are sending from.
If you have a lot of sending domains that you do not own/control, adding a new SPF include in DNS can be a big challenge. To make this easier, we have added the OCI Email Delivery US-based SPF IP ranges to the Dyn SPF; this means you will not have to update DNS for SPF as long as you currently have the Dyn SPF added. However, we strongly recommend working to replace the Dyn SPF for the OCI Email SPF for each domain, to benefit from any changes to the OCI Email SPF.
Add Approved Senders to Your Account
Like Dyn Email Delivery, OCI uses Approved Senders to help ensure good email delivery practices, segment sending activity and reporting, and strengthen use of other features. Each “From” address you plan to use must be added as an Approved Sender. See the guide to Creating an Approved Sender for more helpful information and steps.
Instead of adding Approved Senders manually, you can also use a host of Developer Tools and Resources including Terraform, SDKs, and the OCI CLI to programmatically add senders. This can be combined with the Dyn Email Delivery Approved Senders APIs to perform a seamless migration of all senders.
With your SMTP credentials, email domains, important authentication measures, and approved senders in place, you can start sending. See the guide to Configuring SMTP Connection for info on the region-based connection endpoints and TLS requirements, and Sending an Email for a review of the important setup pieces and links to API and SDK documentation.
Aside from programmatic ways to send email, you can also use tools such as swaks to do very basic send tests using your new configuration.
To check the results of your sending:
data.recipient = testing@company.com
For an introduction to more detailed information on logs and count data (metrics), see the Reporting and Reporting API Quickstart below.
Email Suppression Lists are important to ensure good delivery reputation. You do not need to add suppressions in order to start sending, but before fully moving over we recommend analyzing your current Dyn suppression lists for cleanliness and good email sending reputation.
Depending on your sending practice and list hygiene, you may have a large suppression list built up over time. Ideally, suppression list recipients should only remain on the list for a short time to allow for you to see the update, remove (or fix) the recipient in your own system, then remove the recipient from the suppression list.
If you have kept up with additions to the suppression list and removed or fixed these recipients in your own lists as you go, you can skip migrating the suppression lists since your email list(s) should already be clean. Otherwise, we highly recommend reviewing your suppression list and removing/fixing the recipients in your own lists so you can avoid migrating. This way, you save on email submission costs and have a cleaner start with Oracle Cloud Email Delivery. (Like Dyn Email, Oracle Cloud charges for each email submitted for delivery even if the email recipient is on the suppression list.)
You can cancel your Dyn Email Delivery enterprise account by emailing customersuccess@dyn.com. Note this is not done automatically once you start sending through OCI Email Delivery. Once you are fully done with Dyn Email Delivery, let us know via that email address ASAP.
Cancel Dyn Email Delivery Express Service
After you have fully moved over to OCI Email Delivery and are ready to cancel your Dyn Email Delivery Express service account, login to your account at account.dyn.com with your eCommerce username and password.
This table lists out the main features of Dyn Email, their OCI Email counterparts, and links to documentation were applicable.
Area | Dyn Email Feature | OCI Email Feature | Notes |
---|---|---|---|
Account Structure and Settings | Master and sub-account structure |
Oracle Cloud is a full-featured global cloud with multiple options depending on your requirements:
Read the Overview of Identity and Access Management for a good introduction to Oracle Cloud accounts and organization/access strategies. |
|
Suppression List (One per sub-account) |
Suppression Lists in OCI Email (One per tenancy, always set up in root compartment) |
||
X-Headers |
Custom Headers feature Note: Only email domain log (detail) data supports use of filtering by custom header; metric (count) data does not support custom header filtering |
Custom Headers currently only managed via API or support ticket request; web console availability coming soon | |
Postbacks (bounce, complaint, unsubscribe only) |
Achievable with mix of OCI VCN/subnet, Service Connector, and Functions services. Optionally can integrate the Notifications service but would need Functions in order to pass key log data through and include it in postback/webhook requests. In short, a service connector can be created to key off an Email Domain Log search using whatever field criteria you wish, and then call a function with the log result to send that data out. See Postback Setup below for steps to configure this. |
||
Approved Senders | Approved Senders |
Also: OCI Email introduces the concept of Email Domains which allow for more centralized setup of sender domain-level security and features such as SPF, DKIM, and metrics (count) and log (detail) gathering |
Can be set up in root or other compartment OCI Email does not allow certain public mailbox service provider email addresses to be added as approved senders (such as gmail.com, hotmail.com, yahoo.com) |
Wildcard Senders (*@domain.com) | Enter address as "@domain.com" (no asterisk) | Domain must have DKIM set up and active in order for sender to be created | |
SPF | |||
DKIM | OCI Email strongly recommends use of CNAME records in DNS to set up DKIM, rather than TXT records used in Dyn. This provides for easier rotation of DKIM keys. | ||
Web Interface | OCI web console (https://www.oracle.com/cloud/sign-in.html?redirect_uri=https%3A%2F%2Fcloud.oracle.com%2F) — docs | Dyn ID credentials not transferable; OCI console supports SSO/federated login | |
API | REST API |
OCI Developer Tools (includes CLI, SDKs, REST APIs, DevOps tools like Terraform Provider and Resource Manager) Also see the OCI Email Terraform Quickstart See below for table listing each Dyn Email API method, with mapping to appropriate OCI API |
SDKs exist for Java, Python, TypeScript/JavaScript, .NET, Go, Ruby, and PL/SQL |
Email Submission + Delivery (SMTP + API) | SMTP submission endpoint (smtp.email.dynect.net, plus some customer-specific ones) | OCI Email SMTP regional endpoints | OCI Email SMTP cipher support is more limited but more secure |
Send API | HTTPS Email submission in limited availability, contact us for details | only HTTPS will be supported | |
List-Unsubscribe |
Multiple options:
|
||
"Blackhole" domain for bulk testing (dyn-blackhole.com) | Use discard.oracle.com for testing, to have recipient emails discarded at outbound delivery and not delivered to Internet | ||
Dedicated IPs/Pools | Dedicated IP Addresses feature, available via support ticket, applicable at email domain or sender level | ||
Returns (Bounces, Spam Complaints, Unsubscribes) | Custom Return Path, applicable only to entire customer account (at "master" account level) |
Custom Return Path feature, available via support ticket, applicable at approved sender level The Return-Path address is located in every outbound message's header. By default, we use our own Return-Path address for all customers. Similar to Dyn Email, OCI Email offers the ability to customize this for a few reasons:
We strongly recommend this feature when migrating your Dyn account to OCI Email Delivery. OCI Email can match any approved sender with their own corresponding custom Return-Path (Dyn could only support one for each customer account). Taking advantage of this feature will greatly help your domains deliverability. Read more information and steps to get a custom Return-Path set up in OCI. |
|
Engagement Tracking | Open Tracking | Now in limited availability, contact us for details | |
Click Tracking | Now in limited availability, contact us for details | ||
Custom Tracking Domains | Under development, contact us for timeline details | ||
Reporting / Analytics | Sent Report |
Counts: "EmailsAccepted" metric — see Email Delivery metrics Detail records: email domain "outboundaccepted" logs with "data.action = accept"; logs must be enabled on per-email domain basis first |
See Reporting Quickstart section |
Delivered Report |
Counts: "EmailsRelayed" metric — see Email Delivery metrics Detail records: email domain "outboundrelayed" logs with "data.action = relay"; logs must be enabled on per-email domain basis first |
See Reporting Quickstart section "Relayed" in this case means message was successfully routed to the recipient email provider; see note above under "Reporting" |
|
Blocked Report |
Counts: "EmailsSuppressed" metric — see Email Delivery metrics Detail records: email domain "outboundaccepted" logs with "data.action = accept" and "data.errorType = "Recipient suppressed"; logs must be enabled on per-email domain basis first Note: the "EmailsBlocklist" metric in OCI is not the same as the Dyn "Blocked" report. Blocklist metrics show up when an email wasn't delivered (bounced) because of one of a particular set of reasons having to do with the delivery IP address being on a third-party IP blocklist. These are quite rare, enough that we don't yet even document them; but we do intend to in the future, as the set of reasons is something we can update as new ones come up (which, again, is very rare). These reasons do not involve the recipient address being blocked or on a suppression list -- it's all about whether an IP on an OCI Email outbound delivery server is on a blocklist. Our Deliverability team makes sure that doesn't happen, which is why it's such a rare occurrence. Our default limits and other vetting of customers, and our willingness to kick customers off the service should they start spamming, ensures we don't show up on those lists. |
See Reporting Quickstart section |
|
Bounce Report |
Counts: "EmailsHardBounced" or "EmailsSoftBounced" metrics — see Email Delivery metrics Detail records: email domain "outboundrelayed" logs with "data.action = bounce" and "data.errorType" = "soft" or "hard"; logs must be enabled on per-email domain basis first |
See Reporting Quickstart section |
|
Complaint (Spam) Report |
Counts: "EmailComplaints" metric — see Email Delivery metrics Detail records: email domain "outboundrelayed" logs with "data.action = bounce" and "data.errorType" = "soft" or "hard"; logs must be enabled on per-email domain basis first |
See Reporting Quickstart section |
|
Unsubscribes |
TBD |
Coming June 2023 |
|
Opens Report |
Counts: "EmailOpens" metric Detail records: email domain "outboundrelayed" logs with "data.action = open"; logs must be enabled on per-email domain basis first, and opens tracking must be enabled for the domain/sender |
Now in limited availability, contact us for details |
|
Clicks Report |
Counts: "EmailLinkClicks" metric Detail records: email domain "outboundrelayed" logs with "data.action = click"; logs must be enabled on per-email domain basis first, and click tracking must be enabled for the domain/sender |
Now in limited availability, contact us for details |
Certain features in Dyn have a particular granularity (set per master, per sub-account, per sender, etc.), while OCI may have a different granularity. These are the changes:
Feature | Dyn | OCI |
---|---|---|
SMTP Credentials | per Sub-account | per OCI user |
API Credentials | per Sub-account | per OCI user |
Custom Return Path | per Master Account (customer) | per Email Domain |
Postbacks — Bounce | per Sub-account | for any field in an Email Domain log, so options are numerous |
Postbacks — Complaint | per Sub-account | for any field in an Email Domain log, so options are numerous |
Postbacks — Unsubscribe | per Sub-account | for any field in an Email Domain log, so options are numerous |
Open Tracking | per Sub-account | per Email Domain |
Click Tracking | per Sub-account | per Email Domain |
Custom Tracking Domain | per Approved Sender | per Email Domain |
Custom X-Headers | per Sub-account | per Approved Sender (planning on per Email Domain with self-serve API) |
Apart from the differences in overall feature sets, there are some key differences/improvements to note in moving from Dyn Email Delivery to Oracle Cloud (OCI) Email Delivery.
OCI Email offers two types of reporting data to show customer email activity of the service:
Type | Provided By | Setup Needed | Available Data |
---|---|---|---|
Metrics |
Aggregate, time-series count data
|
Metrics monitoring policies for Email Delivery (inspect and read) |
See Available Metrics in OCI Email documentation
Available dimensions for metric data:
Note: Custom Headers are not available for filtering metric data |
Logging | Detailed event log data
|
EMAIL_DOMAIN_UPDATE and regular Logging Policies required Logs must be enabled on a per-domain basis in order to collect and read them |
See Email Log Details |
Whether you use web console or API or CLI to access email metrics to retrieve aggregate counts, the key to doing this is the metrics query. You can most easily build queries using the Metrics Explorer in the OCI web console; it allows you to choose one or more filters and automatically derives the appropriate query syntax, which you can then use in other areas (including API and CLI) to run metrics searches.
Metrics queries use Oracle's Monitoring Query Language (MQL) standard to identify the:
Steps to build a query in Metrics Explorer:
Here are example queries for some available email-related metrics:
Data Needed | Query (time range specified separate from query) |
---|---|
All emails submitted by the service, by minute | EmailsAccepted[1m].count() |
All emails submitted by the service, by hour | EmailsAccepted[1h].count() |
Emails relayed (that is, successfully relayed to recipient email provider) by all sales.mydomain.com senders, by day | EmailsRelayed[1d]{resourceDomain = "mydomain.com"}.count() |
Hard Bounce count by day | EmailsHardBounced[1d].count() |
Among email submitted by sender marketing@mydomain.com, count of those suppressed ("blocked") per day because recipient is on suppression list | EmailsSuppressed[1d]{resourceId = "ocid1.emailsender.oc1.uk-london-1.amaaaaaaooyoulaa6f5dubcaci7stvzf6vdli6wpzw4mtapdeymtgqokkljq"}.count() Note: resourceId takes the OCID of the approved sender, not thesender email address; you can get the sender OCID from the Approved Senders page. |
Emails opened for mydomain.com senders per day | EmailsOpened[1d].count() |
For API access, utilize the Monitoring service SummarizeMetricsData API method to retrieve data. Like the Metrics Explorer, the method takes a compartment ID and a SummarizeMetricsDataDetails resource object containing date range, namespace ("oci_emaildelivery" in this case), and MQL query.
Note: MQL seems to require double-quotes when filtering by metric dimensions (resourceDomain or resourceId). When using a language like Python and you have any quotes inside your MQL, it is advised to utilize single quotes around your string values in code, and keep double quotes around strings inside the MQL. See below for examples.
Sample Python metrics list and data queries (replace "compartment_id" with your compartment OCID from the Compartments page):
Data Needed | Code Language Phyton |
---|---|
List of available metrics for the "oci_emaildelivery" namespace, sorted by name in ascending order |
Double quotes used above throughout as there is no query involved containing double quotes. |
Count of emails accepted per minute within a one-hour window (12:00-13:00 on 2 March 2023) across all senders and sending domains |
Double quotes used above throughout as there is no query involved containing double quotes. |
Count of bounces per hour for a 30-hour period for emails sent by all mydomain.com senders |
Single quotes used for Python strings so we can still use the required double quotes around the “resourceDomain” value within the MQL query. |
Count of opens per day for a 14-day period for all emails sent by a particular approved sender |
Single quotes used for Python strings so we can still use the required double quotes around the “resourceId” value within the MQL query. |
OCI makes detail log data for Email Delivery activity available through the OCI Logging service. Activity logs are written on a per-email sending domain basis and must be enabled for each domain.
By default, OCI logs activity for most every service whether it comes from web console, API, CLI, or other interfaces. Assuming you have activity, if you do a basic search with no filter you'll see examples such as listing of resources and changes to resources. Email Delivery offers two types of logs to track email domain activity:
You can enable one or both of these logs for each email domain.
This is a summary of the information detailed on the Logging Details for Email Delivery page. See this page for example log entries.
Event | Log Type | Log Filter(s) — assume "AND" for multiple | Notes |
---|---|---|---|
Email accepted for delivery by OCI Email | outboundaccepted | data.action = 'accept' |
|
Email rejected/blocked because recipient is on suppression list | outboundaccepted | data.action = 'accept'
data.errorType = 'Recipient suppressed'
|
data.smtpStatus would have formal reason |
Email successfully relayed to recipient email provider | outboundrelayed | data.action = 'relay' |
|
Emails relayed for a particular custom header value | outboundrelayed | data.action = 'relay' and data.headers."x-campaignid" = '999' |
If custom header field name has any non-alphanumeric characters (such as a dash), the name itself must be surrounded with double quotes |
Email bounced because of outbound delivery issue (recipient unknown, domain unknown, spam-related refusal, etc.) | outboundrelayed | data.action = 'bounce' |
Can further filter on "data.errorType" for type of bounce:
Other fields included which have additional bounce info, such as:
|
Recipient registered spam complaint | outboundrelayed | data.action = 'complaint' |
|
Recipient opened an email | outboundrelayed | data.action = 'open' |
Extra field may have information about recipient's email client and operating system:
|
Opens for a given custom header value | outboundrelayed | data.action = 'open' and data.headers.region = 'Northeast' |
|
Recipient clicked a link in an email | outboundrelayed |
data.action = 'click'
|
TBD |
Similar to OCI metrics (where Email Delivery activity count data is stored), detailed activity log searching relies on queries fashioned from the Logging Query Language to identify scope and filter search results. A very simple, broad example:
search "ocid1.compartment.oc1..aaaaaaaawqhwudf3pag5gohpzslu7tn4rl2d32bufkgmfzzr4wq7aznylpeq"
| type='com.oraclecloud.emaildelivery.emaildomain.outbound*'
| sort by datetime desc
The above example uses a wider scope of an entire compartment (referred to by its OCID) and returns only email submission/inbound and outbound activity log entries for email sending domains that have logging enabled. Results are sorted by date in descending order. Some other more specific examples:
Data Needed | Code |
---|---|
Count of emails accepted for a given custom header value |
|
Failed Submissions for sender domain mycompany.com (no matter the reason) |
("errorType" is not present for successful submissions. We're searching only the "outboundaccepted" log because all failed submissions go there. If you need to search across multiple domains, specify only the compartment OCID and use same filtering clause.) |
Suppressed submissions across all sender domains |
Particularly helpful to know which of your email submissions are being blocked/suppressed because the recipient is on the suppression list |
Successful relayed email (that is, accepted by recipient email provider for delivery) for mycompany.com |
for just sending domain mycompany.com:
You can use just the "source" field to look for sending domain and not specify the log group + log name in the "search" clause; but searching the specific log (like we do here) should be more performant if you have multiple sending domains. |
All hard bounces across all sending domains |
|
Count of opens for a given custom header value |
|
OCI offers SDKs in several major languages and includes the OCI Logging API with its SearchLogs method. This method takes a date/time range and an object with the same logging query syntax used in the web console, and a few other optional fields.
"List" APIs like SearchLogs return a default maximum number of records at a time. If the response has the default max number of records, it should include an "opc-next-page" field. To get subsequent pages of records, invoke the same request with the previous response's "opc-next-page" value specified in the "page" parameter. You may be able to increase the per-page max record count using the "limit" parameter. See OCI API List Pagination for more information and important details.
See the Using the OCI Logging API page for examples in several languages. Some more real-world Email Delivery examples in Python:
Data Needed | Code Language Phyton |
---|---|
Bounces during a three-day period, sent from mycompany.com senders |
|
Emails successfully relayed for all sending domains in a compartment over a one-hour period |
|
All Gmail and Comcast recipients successfully relayed to during a 24-hour period |
|
Count of emails delivered by recipient domain for a given custom header value |
Result:
|
Category | Dyn Email API | OCI Email API Equivalent | Notes |
---|---|---|---|
Endpoints | api.email.dynect.net (or variation) | Each Oracle Cloud region has its own API endpoint, such as:
|
|
Authentication | API Key, one per account, provided:
|
API Key, an RSA key pair generated through OCI user account
Key is used with OCI CLI configuration and loaded through one of many SDKs OCI API Keys work across regions; they are not region-specific; can have multiple OCI API keys for different uses |
OCI requires HTTPS (SSL) access for all API requests |
Accounts | /accounts (GET or POST) /accounts/delete (POST) |
See the Identity API (use Table of Contents in left sidebar to browse the methods) for info on managing resources like users, groups, compartments, and policies. Read the Overview of Identity and Access Management for a good introduction to Oracle Cloud accounts and access. |
|
X-Headers | /accounts/xheaders (GET or POST) | Currently managed only via support ticket to Email Delivery | |
Email Sending Domains | - | Email Domain API (see Table of Contents for links to methods) | |
Approved Senders |
/senders (GET or POST) /senders/details (GET) /senders/status (GET) /senders/delete (POST) |
Approved Sender API (see Table of Contents for links to methods) (strongly recommended to set up Email Domains as well, to facilitate DKIM and other key features) |
|
DKIM | /senders/dkim (POST) | DKIM API (see Table of Contents for links to methods) Requires email domain to be set up first; DKIM is associated with email domain in OCI |
|
Suppressions |
/suppressions (GET or POST) /suppressions/count (GET) /suppressions/activate (POST) /recipients/status (GET) /recipients/activate (POST) ("recipients" is same as "suppression" in this case; they act on the same data) |
Suppression API (see Table of Contents for links to methods) | |
Custom Tracking Domains (V4 API only) |
/custom-domain (POST) /custom-domains (GET) /custom-domain/[id] (GET) /custom-domain/[id]/validity (GET) /custom-domain/[id] (DELETE) /senders (GET) /sender/[id]/custom-domain (GET, POST, PATCH, DELETE) |
Under development, contact us for timeline details | |
Reporting — Sent |
V2
V4
|
For detail records, use OutboundAccepted log with query filter like this to show only successfully submitted emails:
data.action = 'accept' and data.errorType = ''
For counts, use EmailsAccepted metric, available by approved sender or email domain only; custom header filtering not supported, use log with aggregation function to get counts |
"Sent" in Dyn is more about acceptance of the email for processing/delivery Oracle Cloud Developer Resources |
Reporting — Delivered |
V2
V4
|
For detail records, use OutboundRelayed log with query filter like this to show only relayed (delivered to recipient email provider) emails:
data.action = 'relay'
For counts, use EmailsRelayed metric, available by approved sender or email domain only; custom header filtering not supported, use log with aggregation function to get counts |
Oracle Cloud Developer Resources |
Reporting — Issues (V2 only) | /reports/issues /reports/issues/count |
For detail records, use OutboundAccepted log with query filter like this to show failed email submissions:
data.action = 'accept' and data.errorType != ''
Not available as a metric, use log query with aggregation function to get counts |
Oracle Cloud Developer Resources |
Reporting — Bounces |
V2
V4
|
For counts, use EmailsHardBounced and EmailsSoftBounced metrics, available by approved sender or email domain only; custom header filtering not supported, use log with aggregation function to get counts No equivalent to "/bounce/categories" in OCI; values are returned through "data.bounceCategory" field in Log detail. Current list of possible values:
|
Oracle Cloud Developer Resources |
Reporting — "Blocked" (suppressed) |
V2
V4
|
For detail records, use OutboundAccepted log with query filter like this to show only emailed suppressed because recipient is on suppression list:
data.action = 'accept' and data.errorType = 'Recipient suppressed'
For counts, use EmailsSuppressed metric, available by approved sender or email domain only; custom header filtering not supported, use log with aggregation function to get counts No equivalent in OCI for /blocked-email/reasons; Email Domain Log data will have only "Recipient suppressed" in the data.errorType field, no more specific reason |
Oracle Cloud Developer Resources |
Reporting — Complaints (V2 only) | /reports/complaints /reports/complaints/count |
For detail records, use OutboundRelayed log with query filter like this to show only spam complaints:
data.action = 'complaint'
For counts, use EmailComplaints metric, available by approved sender or email domain only; custom header filtering not supported, use log with aggregation function to get counts |
Oracle Cloud Developer Resources |
Reporting — Opens (V2 only) |
/reports/opens /reports/opens/unique /reports/opens/count /reports/opens/count/unique |
For detail records, use OutboundRelayed log with query filter like this to show only opens:
data.action = 'open'
For counts, use TotalEmailsOpened and UniqueEmailsOpened metric, available by approved sender or email domain only; custom header filtering not supported, use log with aggregation function to get counts |
Oracle Cloud Developer Resources |
Reporting — Clicks (V2 only) | /reports/clicks /reports/clicks/unique /reports/clicks/count /reports/clicks/count/unique |
For detail records, use OutboundRelayed log with query filter like this to show only clicks:
data.action = 'click'
For counts, use TotalEmailsClicked and UniqueEmailsClicked metrics, available by approved sender or email domain only; custom header filtering not supported, use log with aggregation function to get counts |
Oracle Cloud Developer Resources |
Send | /send (POST, V2 only) | HTTPS Email submission in limited availability, contact us for details |
Oracle Cloud offers multiple ways to set up automatic notification of email submission- and delivery-related events, similar to the postback feature in Dyn. In addition to the bounce, spam complaint, and unsubscribe events available in Dyn Email Delivery, Oracle Cloud allows for notification based on numerous events and filtering, such as:
For postback-like functionality, we recommend the use of the Service Connector Hub and Logging services within Oracle Cloud to provide the ability to set up automatic log event monitoring. Service Connectors integrate certain Oracle Cloud services together to facilitate data transfer.
In the case of Email Delivery, email domain log data (provided by the Logging service) provide the data for events such as bounces, complaints, unsubscribes, opens, and clicks. The data would then be sent to one of several different services such as the Notification or Functions services, to provide means for sending that data to your own systems.
Oracle Cloud offers various other options to transmit event data, such as with the Streaming service to external systems like Splunk. Contact us to discuss opportunities.
This solution would likely require some refactoring for any existing Dyn HTTP handler code you have, but the setup on the Oracle Cloud side is relatively simpler and less involved compared to the Function Code solution below — so it is worth exploring. The solution involves integrating the Notification service to send event data to one of several targets:
This solution sends event data in JSON blob form; so your code behind that URL would need to parse out the JSON to pull out the appropriate fields, similar to any existing HTTP handler code you have. Follow the basic steps below to set up an example notification "postback".
Email Domain event log data is structured differently than in Dyn Email so any existing code will need to be refactored to match. Most email domain log data will look like this (though some fields will differ depending on the event type):
{
"data": {
"action": "bounce",
"bounceCategory": "bad-mailbox",
"bounceCode": "5.1.1",
"errorType": "hard",
"message": "Suppressed recipient invalid-recipient@gmail.com for email from sender@mydomain.com: bad-mailbox hard bounce",
"messageId": "20230404133157.059822@source-server",
"originalMessageAcceptedTime": "2023-04-04T17:31:58.807Z",
"receivingDomain": "domain.com",
"recipient": "invalid-recipient@gmail.com",
"recipientMailServer": "gmail-smtp-in.l.google.com (TCP|130.35.116.120|41521|173.194.76.27|25) (mx.google.com ESMTP b16-20020ad8139351002e63fddfad8909160wrn.440 - gsmtp)",
"reportGeneratedTime": "2023-04-04T17:31:58Z",
"sender": "sender@mydomain.com",
"senderCompartmentId": "ocid1.compartment.oc1..aaaaaaaawqhwudf3pag5gohpzslu7tn4rl2d32bufkgmfzzr4wq7aznylpeq",
"senderId": "ocid1.emailsender.oc1.uk-london-1.amaaaaaaooyoulaawiybkhjpvsfkm3jsey3bmmzfwoca3yjk7uiq2s3xt4ga",
"smtpStatus": "550-5.1.1 The email account that you tried to reach does not exist. Please try the recipient's email address for typos or spaces. Learn more at https://support.google.com/mail/?p=NoSuchUser b16-20020adfe650000000"
},
"id": "bc55d3d4-b33c-4c3c-98f8-d3c0b9af5bf3",
"oracle": {
"compartmentid": "ocid1.compartment.oc1..aaaaaaaawqhwudf3pag5gohpzslu7tn4rl2d32bufkgmfzzr4wq7aznylpeq",
"ingestedtime": "2023-04-04T17:32:06.826Z",
"loggroupid": "ocid1.loggroup.oc1.uk-london-1.amaaaaaaooyoulaa7f2hx3ebgdkfnhbhnemsmgq7cpoilzxjcd6yh5df46ta",
"logid": "ocid1.log.oc1.uk-london-1.amaaaaaaooyoulaa5xmtlvnez5ekyfdmr5sbw5qywb5jxggyjcmucfst2iva",
"tenantid": "ocid1.tenancy.oc1..aaaaaaaapgqj5fjeku52qogywp4agshdscgog4gaeuk5uxfccyx5fofpg2oa"
},
"source": "mydomain.com",
"specversion": "1.0",
"time": "2023-04-04T17:32:00.221Z",
"type": "com.oraclecloud.emaildelivery.emaildomain.outboundrelayed"
}
Fields above such as "bounceCategory" and "bounceCode" will not be present for non-bounce events. Other field values will differ for other event types, such as "action", "errorType", "smtpStatus", and "message". See the Email Log Searching section of this guide for more information.
Note that Service Connector Hub will batch multiple log entries into a single request if they occur close enough to each other, so your handler should be able to handle multiple log entries within a single JSON request body.
Follow these steps to enable logging for one or more of your sending email domains. Once this is done, you will start to see helpful event logging to gain insight into your sending activity, in addition to automatic metrics.
To utilize the Notification Service as a target for email domain event log data, you must first set up a topic and subscription. Dyn customers who wish to keep their postback solution would use the HTTPS URL type of subscription, but you can use other types instead.
For HTTPS URL subscriptions you must first host your HTTP handler on a secure website because the setup process will send an HTTP POST to the handler with a confirmation link in the request body. This URL must be opened to confirm the handler is reachable and enable it for active use.
While you can create a Service Connector through the Service Connector Hub web console UI, it is easier to first define your email domain log search criteria, then create a service connector from there.
At this point, any log events that occur which match your log search criteria, will be sent to your HTTPS URL via HTTP POST, and the body will contain one or more log events.
Inspired by Nitin Soni's solution. Other function samples available via the Oracle Functions Samples repo on GitHub.
This solution provides postback-like functionality without need to modify existing customer HTTP handler code, by utilizing Oracle Cloud's Service Connector Hub to integrate email domain log events with the Functions service. Function code would be written and deployed within Oracle Cloud to make HTTPS requests to your existing or new web postback handler. For a much simpler but less flexible alternative, see the Postbacks via Notification section.
Follow these steps to enable logging for one or more of your sending email domains. Once this is done, you will start to see helpful event logging to gain insight into your sending activity, in addition to automatic metrics.
Functions are used as a sort of "callback" to perform a notification or other business action as a result. Combined with Service Connectors (below), you can set up automatic notification for one or more events such as a bounce, spam complaint, open, click, etc.
A more detailed quickstart is available, and you can import template functions as well, but here are the basic steps to set up a function:
Replace the contents of func.py with the following, which is a sample email bounce event notification:
"""
OCI Function for Email Delivery Event Notification (Python example)
This function takes one or more OCI Email Domain log events and sends HTTP "postback"
notifications to a website address, similar to the Dyn Postback feature.
This function can be modified to support any type of log item.
Requirements/Dependencies:
OCI Email Delivery service configuration (https://docs.oracle.com/en-us/iaas/Content/Email/Reference/gettingstarted.htm)
- user with SMTP credentials
- required policies
- email domain with SPF + DKIM set up
- email domain logging enabled
- approved sender created
OCI Functions configuration (https://docs.oracle.com/en-us/iaas/Content/Functions/Tasks/functionsquickstartcloudshell.htm)
- VCN + subnet (private, using NAT Gateway)
- required policies
- application (with optional logging enabled)
- function with code to read Log and send HTTP request
OCI Service Connector Hub integration with Logging (https://docs.oracle.com/en-us/iaas/Content/service-connector-hub/create-service-connector-logging-source.htm)
- service connector using:
-- VCN subnet
-- Logging as source, pointed at Email Domain "outboundrelayed" log, and log rule task of "data.action = bounce" (can fine-tune this to be more or less granular)
-- OCI Function as target
"""
import io
import json
import logging
import requests
from fdk import response
bounce_postback_url_with_params = "https://mydomain.com/dyn-http-handler.php?type=b&e={email}&bt={bouncetype}&bc={bouncecode}&br={bouncerule}&dc={diagnostic}&s={status}&message={message}"
bounce_postback_url_no_params = "https://mydomain.com/dyn-http-handler.php"
def handler(ctx, data: io.BytesIO=None):
"""
Main Function handler routine, takes
"""
# Input is one or more Log events; parse into JSON and loop through them
try:
logs = json.loads(data.getvalue())
for item in logs:
# Pull postback field values from log event
log_data = item['logContent']['data']
# For custom headers, gather them (if present) and loop through to add to request parameters
#headers = log_data['headers'] # gives a dictionary of (header_name -> value) pairs
# Other possibly helpful fields to include, which were not available in Dyn:
# (see https://docs.public.oneportal.content.oci.oraclecloud.com/en-us/iaas/Content/Logging/Reference/details_for_emaildelivery.htm for list of all available fields)
#event_time = item['logContent']['time'] # ISO 8601 format; for epoch time, use item['datetime']
message = log_data['message'] # this is high-level, human-readable summary of bounce reason
#message_id = log_data['messageId'] # original SMTP message ID
#action = log_data['action'] # type of log event (accept, relay, bounce, open, click, etc.)
#sender = log_data['sender'] # sender of the message
#recip_domain = log_data['receivingDomain'] # Recipient domain (gmail.com, comcast.net, hotmail.com, etc.)
params_values = {
"email": log_data['recipient'],
"bouncetype": log_data['errorType'],
"bouncecode": log_data['bounceCode'],
"bouncerule": log_data['bounceCategory'],
"diagnostic": log_data['smtpStatus'],
"status": log_data['bounceCode'],
"message": message
}
# Traditional URL querystring GET method, no request body
http_response = requests.get(bounce_postback_url_with_params.format(**params_values))
# GET with parameters passed in request body
#http_response = requests.get(bounce_postback_url_no_params, params=params_values)
# POST with parameters passed in request body
#http_response = requests.post(bounce_postback_url_no_params, data=params_values)
logging.getLogger().info("Postback sent: {} Response: HTTP {} --- {}".format(http_response.url, http_response.status_code, http_response.text.replace('\n', '')))
except (Exception, ValueError) as ex:
logging.getLogger().error(str(ex))
return
Editor will automatically save code updates by default, but click File menu, then Save to be sure.
Double-click requirements.txt in the left pane to open that file, then add "requests" to the list of Python packages ensure it will be imported:
fdk
requests
Click File → Save.
fn list context
fn use context [long_region_name] (replace region long name as appropriate)
fn update context oracle.compartment-id ocid1.[compartment_ocid] (OCID for root compartment is the tenancy OCID)
fn update context registry [short_region_code].ocir.io/[tenancy-namespace]/[repo-name-prefix] (replace "lhr" with region short name, such as phx, iad, fra, syd)
docker login -u '[tenancy-namespace]/[oci-username]' lhr.ocir.io (or phx, iad, fra, syd, etc.)
cd ~/oci-ide-plugins/faas-artifacts/[application_ocid]/bounce-notification/
git init
git add .
git commit -m 'Initial commit of function code'
git remote add origin <(URL of code repository created above)>
git branch -M main
git push -u origin main
fn -v deploy --app email-event-notifications-app
echo -n '[{"datetime":1678283756324,"logContent":{"data":{"action":"accept","envelopeSender":"erik+test@mydomain.com","errorType":"Recipient suppressed","message":"Suppressed email from erik+test@mydomain.com → nowaythisisreal6543210@mydomain.com","principalId":"ocid1.user.oc1..aaaaaaaajf6yi5qzyb35af3fxj454n4kyjfyurdvdcnodkjkvg2dabr2uzdq","receivingDomain":"mydomain.com","recipient":"nowaythisisreal6543210@mydomain.com","senderCompartmentId":"ocid1.compartment.oc1..aaaaaaaawqhwudf3pag5gohpzslu7tn4rl2d32bufkgmfzzr4wq7aznylpeq","senderId":"ocid1.emailsender.oc1.uk-london-1.amaaaaaaooyoulaa6f5dubcaci7stvzf6vdli6wpzw4mtapdeymtgqokkljq","smtpStatus":"254 4.7.1 - nowaythisisreal6543210@mydomain.com is suppressed for sender ocid1.emailsender.oc1.uk-london-1.amaaaaaaooyoulaa6f5dubcaci7stvzf6vdli6wpzw4mtapdeymtgqokkljq"},"id":"cedfaf44-89a9-4a6e-8057-233a0176b0a3","oracle":{"compartmentid":"ocid1.compartment.oc1..aaaaaaaawqhwudf3pag5gohpzslu7tn4rl2d32bufkgmfzzr4wq7aznylpeq","ingestedtime":"2023-03-08T13:56:03.976Z","loggroupid":"ocid1.loggroup.oc1.uk-london-1.amaaaaaaooyoulaa7f2hx3ebgdkfnhbhnemsmgq7cpoilzxjcd6yh5df46ta","logid":"ocid1.log.oc1.uk-london-1.amaaaaaaooyoulaao3cik345bpfz44miozkxiqi4chucpnjawl4lvxxezenq","tenantid":"ocid1.tenancy.oc1..aaaaaaaapgqj5fjeku52qogywp4agshdscgog4gaeuk5uxfccyx5fofpg2oa"},"source":"mydomain.com","specversion":"1.0","time":"2023-03-08T13:55:56.324Z","type":"com.oraclecloud.emaildelivery.emaildomain.outboundaccepted"}}]' | fn invoke email-event-notifications-app bounce-notification
The Service Connector Hub service in Oracle Cloud offers the ability to integrate services within the cloud and pass information between them. In this case, we're connecting the Logging service (which stores activity for Email Delivery sending domains) with the Functions service (which will accomplish the HTTP postback call). Log data is passed between the services, providing a great deal of flexibility and power in creating a custom solution for your needs.
For Log filter task, choose one or more filters to limit the scope of the notifications for this function. For instance, these two filters will catch all emails blocked from delivery because the recipient is on the suppression list:
data.action = accept
data.errorType = Recipient suppressed
As you add filters, you can see the query syntax update on the right, and can click "View logs" to see any matches for that filter in the last six hours. Note that a service connector can only
We have two OCI Function samples available to cover the various types of OCI Email events. With the Service Connector / Functions integration detailed above, each connector with a Logging source can only pull from a single log at a time. Email domain activity is contained in two different logs (“outboundaccepted” and “outboundrelayed”). If you want to cover all the events listed above in the "Email Domain Log Events and Filtering" table you would need to create two service connectors: one to cover the events in outboundaccepted, the other for events in outboundrelayed.
Log | Events Covered |
---|---|
outboundaccepted |
|
outboundrelayed |
|