AWS for SAP

Amazon SES configuration for SAP ABAP Systems – Part II

Overview

This is a part II of Blog Amazon SES configuration for SAP ABAP Systems
In part I, we covered the Outbound emails from SAP systems to external recipients. In this blog, we will cover Inbound email from external recipients to SAP users.

Services Used

    • Amazon Simple Email Service
    • AWS Lambda
    • Amazon CloudWatch Logs
    • Amazon S3

Introduction

In previous blog, we showed how AWS Native services can be leveraged for outbound mail notifications from SAP systems. In this blog we will guide you through the required steps to configure inbound mail to an SAP ABAP system using Amazon SES (Simple Email Service) service.

Amazon Simple Email Service (SES) is a cost-effective, flexible, and scalable email service that enables customers to send mail from within any application. You can configure Amazon SES quickly to support several email use cases, including transactional, marketing, or mass email communications

For a detailed list of SES service capabilities specific to inbound email processing see documentation. In our example we will call a Lambda function to process and deliver the mail (including any attachment) to a named SAP user.

Architecture

RISE with SAP

RISE with SAP architecture diagram

Figure 1: RISE with SAP architecture diagram

SAP on AWS Native

SAP on AWS Native Deployment

Figure 2: SAP on AWS Native Deployment

Workflow

  1. End user sends email to the target system e.g. x12@people.aws.dev
  2. The request is handled by inbound-smtp.eu-central-1.amazonaws.com (Amazon SES SMTP endpoint for inbound requests for the specific region e.g. eu-central-1 in this case)
  3. Email is saved in Amazon S3 bucket
  4. Lambda function is invoked. This function will send the email saved in Amazon S3 bucket to the local SMTP service for the target SAP system
  5. SAP system will receive the email

Prerequisites

As documented in this page, the following steps need to be performed

S3 bucket and its permissions

This bucket is required for storing mails which will be forwarded to target SAP system. Below is an example bucket policy to be linked to this bucket. Please find some example in the AWS documentation. In our example we grant SES service access to an S3 bucket for copying mail objects.

You can set lifecycle policy on the S3 bucket used to store the incoming emails, for management. For example, after 10 days, move them to Infrequent Access storage class OR after 30 days, delete them.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "sid1",
            "Effect": "Allow",
            "Principal": {
                "Service": "ses.amazonaws.com"
            },
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::<s3-bucket-name>/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceAccount": "<AWS Account Number>"
                },
                "StringLike": {
                    "AWS:SourceArn": "arn:aws:ses:*"
                }
            }
        }
    ]
}

Domain verification

Amazon SES domain verification is done via identity creation under the configuration identities menu; ensure the Identity Status is “Verified

Figure 4: Domain Verification status

Figure 3: Domain Verification status

Publishing MX record

In this case we are using Amazon Route53 as dns, and created a MX record which points our domain to the Amazon SES endpoint

Figure 4: MX record DNS configuration for Route53

Figure 4: MX record DNS configuration for Route53

Validate SAP system connection details

SAP system hostname/IP address and SMTP port. This last information can be extracted from SAP transaction smicm → active services. In our solution, Amazon SES will be communicating with the SAP system on this SMTP port. This port needs to be whitelisted to allow Amazon SES to communicate.

Figure 5: ICM service settings

Figure 5: ICM service settings

Lambda function

Please create the Lambda function with VPC access in order to connect to the target SAP system (see screenshot for reference).

Security group should allow outgoing traffic on the SMTP configured port in SAP and outgoing traffic to S3 endpoints. For example, in below diagram, SMTP services on SAP system is configured to listen on port 25000 and S3 endpoint on port 443.

Figure 6: Lambda function VPC settings

Figure 6: Lambda function VPC settings with security group rules

Also ensure that this function has access to write Cloudwatch logs and access to read contents from S3 bucket, where emails are stored

Lambda code which will be invoked by SES service upon receiving an inbound message (code has been adjusted for SAP from original SES blog)

# Copyright 2010-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. 
# 
# This file is licensed under the Apache License, Version 2.0 (the "License"). 
# You may not use this file except in compliance with the License. A copy of the 
# License is located at 
# 
# http://thinkwithwp.com/apache2.0/ 
# 
# This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
# OF ANY KIND, either express or implied. See the License for the specific 
# language governing permissions and limitations under the License.
import smtplib
import os
import boto3
import re
import email
from email.message import EmailMessage
from email.parser import BytesParser, Parser
from email.policy import default
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication

host = "<hostname or IP of SAP target system>"
port = "<port of SAP SMTP service>"
region = os.environ['AWS_REGION']

def lambda_handler(event, context):

# Get the unique ID of the message. This corresponds to the name of the file
# in S3.
message_id = event['Records'][0]['ses']['mail']['messageId']

# Retrieve the file from the S3 bucket.
file_dict = get_message_from_s3(message_id)

# Create the message.
message = create_message(file_dict)

# Send the email and print the result.
smtp = smtplib.SMTP(host, port)
smtp.ehlo()
result = smtp.send_message(message)
smtp.close()

def get_message_from_s3(message_id):

incoming_email_bucket = "<bucket name to store the messages>"
incoming_email_prefix = "ses"

if incoming_email_prefix:
object_path = (incoming_email_prefix + "/" + message_id)
else:
object_path = message_id

object_http_path = (f"http://s3.console.thinkwithwp.com/s3/object/{incoming_email_bucket}/{object_path}?region={region}")

# Create a new S3 client.
client_s3 = boto3.client("s3")

# Get the email object from the S3 bucket.
object_s3 = client_s3.get_object(Bucket=incoming_email_bucket, Key=object_path)
# Read the content of the message.
file = object_s3['Body'].read()

file_dict = {
"file": file,
"path": object_http_path
}

return file_dict

def create_message(file_dict):

separator = ";"

# Parse the email body.
mailobject = email.message_from_string(file_dict['file'].decode('utf-8'), policy=email.policy.default)
#print(mailobject)

# Extract sender,receiver and subject.
sender = mailobject['From']
receiver = mailobject['To']
subject = mailobject['Subject']

# Create body text of the email for sending as attachment
body_text = ("The attached message was received from " + separator.join(mailobject.get_all('From')) + ". This message is archived at " + file_dict['path'])

# Extract body text of the email.
body = mailobject.get_body(preferencelist=('related', 'html', 'plain'))
attachment = mailobject.get_payload()[1]

# The file name to use for the attached message. Uses regex to remove all
# non-alphanumeric characters, and appends a file extension.
filename = re.sub('[^0-9a-zA-Z]+', '_', subject) + ".eml"

# Create a MIME container.
msg = MIMEMultipart()
# Create a MIME text part.
text_part = MIMEText(body_text, _subtype="html")
# Attach the text part to the MIME message.
msg.attach(body)

# Add subject, from and to lines.
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = receiver

# Attach the file object to the message.
msg.attach(attachment)
message = msg
return message

SES Rule Set

In SES console, under configuration → mail receiving, add a new rule which will first store the message in S3 bucket and then invoke the Lambda function which was just created to process the message and send it to SAP (including any attachment).

Figure 7: Amazon SES Ruleset

Figure 7: Amazon SES Ruleset

SAP ABAP Inbound Email Configuration

Test inbound email

For inbound email testing, write an email to the recipient which was just configured in the rule set above.

Figure 8: Test Email

Figure 8: Test Email

Once sent, we can check in SAP system’s user inbox (which needs proper mail address setup in user master data – transaction su01) using transaction so01

Figure 9: SAP mailbox

Figure 9: SAP mailbox

Costs

Below are the services and relevant monthly costs associated with the use of those services for this solution. Let us assume every month 40,000 emails are received by the system with each email of size 40KB (Public link is here)

  • Amazon SES – 8 USD
  • Amazon Route 53 – 0.52 USD
  • Amazon S3 Bucket – 0.27 USD
  • Amazon CloudWatch Logs – 0.95 USD
  • AWS Transit Gateway (optional, in case of SAP RISE deployments) – 43.83 USD
  • Amazon Lambda – 6.69 USD

Total cost is estimated at 60.26 USD per month for Frankfurt region.

Conclusion

In this blog, we have shown how to configure SAP ABAP systems for receiving inbound emails, a very common requirement, both from Business processes and Basis operations perspectives. More information can be found in the SES documentation.

Let us know if you have any comments or questions — we value your feedback.