Note:

Set Up Email Notifications for Oracle Cloud Infrastructure Events in OCI Monitoring

Introduction

Oracle Cloud Infrastructure (OCI) services emit events, which are structured messages that indicate changes in resources. It is required to create rules to work with events and also specify an action to trigger when it finds a matching event.

Email notification actions is a response which you define for event matches. OCI email delivery service provides a fast and reliable managed solution for sending secured, high-volume and transactional email notifications.

Objectives

Prerequisites

Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) administrator should create:

For more information about subscribed and preferred email delivery region, see Configuring SMTP Connection Endpoint.

Task 1: Configure approved sender in email delivery

An approved sender must be set up for all “From:” addresses sending mail through OCI. It is associated with a compartment and only exists in the region where the approved sender was configured.

You can use your domain name or default oracle notification for approved sender as mentioned below.

  1. Open the navigation menu of OCI Console and click Developer Services.

  2. Under Application Integration, click Email Delivery.

  3. Under Email Delivery, click Approved Senders.

  4. Click Create Approved Sender and enter the email address that you want to list as an approved sender.

    Note: If your OCI email delivery SMTP connection endpoint is smtp.email.ap-mumbai-1.oci.oraclecloud.com then add noreply@notification to region and enter in approved sender email address. For example, noreply@notification.ap-mumbai-1.oci.oraclecloud.com.

  5. Click Add to add email address to your Approved Senders list.

Task 2: Create Tag namespace and key definition

  1. Open the navigation menu and click Governance & Administration.

  2. Under Tenancy Management, click Tag Namespaces.

  3. On the Tag Namespaces page, click Create Tag Namespaces.

  4. In the Create Tag Namespace panel, select the appropriate compartment and type custom in namespace name and provide description.

  5. On custom namespace, click Create Tag Key Definitions and type recipient in Tag key and create it.

    Note: You can add the recipient email addresses to the defined tag in each OCI resource, where notification required. The solution will use recipient addresses to notify, if available in Cloud event, else defaultrecepient address will be used specified in function configuration. For example, demouser1@abc.com,demouser2@abc.com

Task 3: Create secret in OCI vault

  1. Open the navigation menu, click Identity & Security, and then click Vault.

  2. Under List scope, select a compartment that contains the vault.

    Note: If you need to create a new vault and master encryption key, follow the instructions in Create Vault and Master Encryption Key.

  3. Under Resources, click Create Secret and select appropriate master encryption key.

    • Enter smptppass in name field and description SMTP password for OCI email delivery authentication.

    • Select the format plain-text for Secret Type Template and enter smtp password, for contents of the secret.

      Note: Use SMTP password shared by OCI IAM admin.

Task 4: Create and deploy OCI function

  1. On OCI console, click Cloud Shell in the top navigation.

  2. Create function using Fn project CLI from cloud shell.

    fn init --runtime python <function-name>
    
    Example: fn init --runtime python emaildelivery-func
    
  3. Change directory to the newly created directory.

  4. Create app to deploy the function.

    # Specify the OCID of subnet
    fn create app emaildeliveryapp --annotation oracle.com/oci/subnetIds='["<subnet OCID>"]'
    
    Example:  fn create app emaildeliveryapp --annotation oracle.com/oci/subnetIds='["ocid1.subnet.oc1.ap-mumbai-1.aaaaaaaabitp32dkyox37qa3tk3evl2nxivwb....."]'
    
  5. Copy and paste below script in the func.py file by overwriting the existing content.

    # python script for sending SMTP configuration with Oracle Cloud Infrastructure Email Delivery
    import io
    import json
    import logging
    import oci
    from fdk import response
    import smtplib
    import email.utils
    import ssl
    import base64
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    from email.mime.base import MIMEBase
    
    # Get Resource Principal Credentials
    signer = oci.auth.signers.get_resource_principals_signer()
    
    # Get instance principal context
    secret_client = oci.secrets.SecretsClient(config={}, signer=signer)
    identity_client = oci.identity.IdentityClient(config={}, signer=signer)
    tenancy_data = identity_client.get_tenancy(tenancy_id=signer.tenancy_id).data
    t_name = str(tenancy_data.name)
    t_id = signer.tenancy_id
    
    # Retrieve secret
    def read_secret_value(secret_client, secret_id):
       response = secret_client.get_secret_bundle(secret_id)
       base64_Secret_content = response.data.secret_bundle_content.content
       base64_secret_bytes = base64_Secret_content.encode('ascii')
       base64_message_bytes = base64.b64decode(base64_secret_bytes)
       secret_content = base64_message_bytes.decode('ascii')
       return secret_content
    
    # Sender name
    sendername = 'noreply'
    
    # If you're using Email Delivery in a different region, replace the HOST value with an appropriate SMTP endpoint.
    # Use port 25 or 587 to connect to the SMTP endpoint.
    port = 587
    
    # Reading company logo information in base64 encoded
    with open("companylogo.png", "rb") as image_file:
       image_data = base64.b64encode(image_file.read())
    image_data = '<img src="data:image/png;base64,'+str(image_data)[2:]+'" alt="company logo" />'
    
    def handler(ctx, data: io.BytesIO=None):
       try:
          # Extracting function config values
          cfg = ctx.Config()
          smtp_user = cfg["smtpuser"]
          host = cfg["host"]
          sender = cfg["sender"]
          smtp_defrec = cfg["defaultrecipient"]
          smtp_pass = cfg["smtppass"]
    
          # Secrets from vault
          smtp_pass = read_secret_value(secret_client, secret_id=smtp_pass )
    
          # Extracting values from triggered OCI event
          body = json.loads(data.getvalue())
          e_Type = body.get("eventType")
          e_time = body.get("eventTime")
          r_name = body["data"]["resourceName"]
          c_id = body["data"]["compartmentId"]
          c_name = body["data"]["compartmentName"]
          r_id = body["data"]["resourceId"]
          add_detail = ""
    
          try:
                # Extracting additional details from OCI event
                details = body["data"]["additionalDetails"]
                for key, value in details.items():
                   add_detail = add_detail+str(key)+' : '+str(value)+'<br>'
          except (Exception, ValueError) as ex:
                add_detail = "Additional details not available for this OCI event"
    
          try:
                # Extracting recepient details if available in OCI event
                recipient = body["data"]["definedTags"]["custom"]["recipient"]
          except Exception as e:
                recipient = smtp_defrec
    
          # Extract event type
          e_Type = e_Type.split('com.oraclecloud.')[1]
    
          # Extract region name
          r_id = r_id.split('.')[3]
    
          # The subject line of the email.
          SUBJECT = 'Event | '+ r_name + ' | ' + e_Type + ' | ' + e_time
    
          BODY_HTML = """\
          <html>
             <head></head>
             <body>
             """ +str(image_data)+ """
             <h2>Oracle Cloud Notification</h2>
             <hr>
             <b>Event Time : </b>""" +str(e_time)+ """
             <br>
             <b>Event Type : </b>""" +str(e_Type)+ """
             <br>
             <b>Tenancy Name : </b>""" +str(t_name)+ """
             <br>
             <b>Tenancy ID : </b>""" +str(t_id)+ """
             <hr>
             <b>Resource Name : </b>""" +str(r_name)+ """
             <br>
             <b>Region Name : </b>""" +str(r_id)+ """
             <br>
             <b>Compartment ID : </b>""" +str(c_id)+ """
             <br>
             <b>Compartment Name : </b>""" +str(c_name)+ """
             <hr>
             <b>Details : </b><br>""" +str(add_detail)+ """
             <hr>
          <br>
          <p>
          Thank you, <br>
          The OCI team <br><br><br>
          Please do not reply directly to this email. This mailbox is not monitored. If you have any questions regarding this notification, contact your account administrator. <br>
          </p>
          </body>
          </html>
          """
    
          # create message container
          msg = MIMEMultipart()
          msg['Subject'] = SUBJECT
          msg['From'] = email.utils.formataddr((sendername, sender))
          msg['To'] = recipient
    
          # Attach HTML body for email
          msg.attach(MIMEText(BODY_HTML, 'html'))
    
          # Attach JSON payload as attachement
          attach_file = json.dumps(body,indent=2)
          payload = MIMEBase('application', 'octate-stream')
          payload.set_payload(attach_file)
          payload.add_header('Content-Disposition', 'attachment', filename='event_output.json')
          msg.attach(payload)
    
          # Try to send the message.
          server = smtplib.SMTP(host, port)
          server.ehlo()
          # most python runtimes default to a set of trusted public CAs that will include the CA used by OCI Email Delivery.
          # However, on platforms lacking that default (or with an outdated set of CAs), customers may need to provide a capath that includes our public CA.
          server.starttls(context=ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH, cafile=None, capath=None))
          # smtplib docs recommend calling ehlo() before & after starttls()
          server.ehlo()
          server.login(smtp_user, smtp_pass)
    
          # our requirement is that SENDER is the same as From address set previously
          server.sendmail(sender, recipient, msg.as_string())
          server.close()
          # Display an error message if something goes wrong.
       except (Exception, ValueError) as ex:
          logging.getLogger().info('error parsing json payload: ' + str(ex))
    
       return response.Response(ctx, response_data=json.dumps({"message": "success"}),headers={"Content-Type": "application/json"})
    
  6. You could replace companylogo.png with your company logo and update HTML text as email body in script. Default is Oracle logo.

  7. Run below command to deploy the function.

    fn -v deploy --app <app-name>
    
    Example: fn -v deploy --app emaildeliveryapp
    
  8. Execute below to add function configuration for each config key and value.

    • sender: Use approved sender configured in Task 1.

    • smtpuser: SMTP user shared by OCI IAM admin.

    • smtppass: Use OCID of SMTP password vault secret and update in smtppass config value.

    • host: Use SMTP connection endpoint as per prerequisite.

    • defaultrecipient: Provide email address as default recipient. The solution will use _recipient addresses_ to notify, if available in Cloud event, else _defaultrecepient_ address will be used in function configuration.

    fn config function <app-name> <function-name> <config-key> <config-value>
    
    Example: fn config function emaildeliveryapp emaildelivery-func sender noreply@notification.ap-mumbai-1.oci.oraclecloud.com
    

Task 5: Create event rule

  1. Open the navigation menu and click Observability & Management.

  2. Under Events Service, click Rules.

  3. Click Create Rule and in the Create Rule panel, provide a friendly name for the rule and a description of what the rule does.

  4. In the Rule Conditions area, specify event type and action to trigger function. You can define filters based on event types, attributes, and tags to limit the events that trigger actions. Below is example to trigger compute instance start or stop event.

    compute instance event rule

Task 6: Validate email notification

  1. Start or stop the compute instance in compartment where event rule was created to trigger the OCI event.

  2. You will receive email friendly notification, along with raw JSON attached to it.

    email notification

Acknowledgments

Author - Dipesh Kumar Rathod (Master Principal Cloud Architect, Infrastructure)

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.