简体   繁体   中英

“Name or service unknown” error when App Engine calls Amazon SES (Simple Email Service)

Sometimes -- not always -- I get a name or service not known error when calling Amazon SES from Google App Engine / Python 2.7.

I'm calling Amazon's sample code, which I'll paste at the end of this question, but it's available here: https://docs.aws.amazon.com/ses/latest/DeveloperGuide/examples-send-using-smtp.html

Of course I put in my Amazon account credentials, and use a white-listed email address to send, and a valid address to receive. The code works flawlessly, every time, when I run it on my desktop Python system.

Here is the back-trace:

File "/base/data/home/apps/m~/1.4222/emailer_test.py", line 79, in <module>
    server = smtplib.SMTP(HOST, PORT)
  File "/base/alloc/tmpfs/dynamic_runtimes/python27g/79cf/python27/python27_dist/lib/python2.7/smtplib.py", line 256, in __init__
    (code, msg) = self.connect(host, port)
  File "/base/alloc/tmpfs/dynamic_runtimes/python27g/79cf/python27/python27_dist/lib/python2.7/smtplib.py", line 316, in connect
    self.sock = self._get_socket(host, port, self.timeout)
  File "/base/alloc/tmpfs/dynamic_runtimes/python27g/79cf/python27/python27_dist/lib/python2.7/smtplib.py", line 291, in _get_socket
    return socket.create_connection((host, port), timeout)
  File "/base/alloc/tmpfs/dynamic_runtimes/python27g/79cf/python27/python27_dist/lib/python2.7/socket.py", line 560, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
gaierror: [Errno -2] Name or service not known

I haven't figured out anything that might cause it to fail some times on App Engine and not others. This StackOverflow question talks about configuring the firewall for MailGun.

Java Google App Engine won't send email via Mailgun SMTP

I'd have to turn on billing to configure the firewall, and I don't want to unless necessary. Plus, why would it work sometimes if it were a firewall configuration error?

Here is Amazon's sample code, adapted as I use it. Also, my SES account is in the West-2 (Oregon) zone.

import smtplib  
import email.utils
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# Replace sender@example.com with your "From" address. 
# This address must be verified.
SENDER = 'sender@example.com'  
SENDERNAME = 'Sender Name'

# Replace recipient@example.com with a "To" address. If your account 
# is still in the sandbox, this address must be verified.
RECIPIENT  = 'recipient@example.com'

# Replace smtp_username with your Amazon SES SMTP user name.
USERNAME_SMTP = "smtp_username"

# Replace smtp_password with your Amazon SES SMTP password.
PASSWORD_SMTP = "smtp_password"

# (Optional) the name of a configuration set to use for this message.
# If you comment out this line, you also need to remove or comment out
# the "X-SES-CONFIGURATION-SET:" header below.
CONFIGURATION_SET = "ConfigSet"

# If you're using Amazon SES in an AWS Region other than US West (Oregon), 
# replace email-smtp.us-west-2.amazonaws.com with the Amazon SES SMTP  
# endpoint in the appropriate region.
HOST = "email-smtp.us-west-2.amazonaws.com"
PORT = 587

# The subject line of the email.
SUBJECT = 'Amazon SES Test (Python smtplib)'

# The email body for recipients with non-HTML email clients.
BODY_TEXT = ("Amazon SES Test\r\n"
             "This email was sent through the Amazon SES SMTP "
             "Interface using the Python smtplib package."
            )
import time
# The HTML body of the email.
BODY_HTML = """<html>
<head></head>
<body>
  <h1>Amazon SES SMTP Email Test</h1>
  <p>This email was sent with Amazon SES using the
    <a href='https://www.python.org/'>Python</a>
    <a href='https://docs.python.org/3/library/smtplib.html'>
    smtplib</a> library at %s.</p>
</body>
</html>
            """ % time.asctime()

# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = SUBJECT
msg['From'] = email.utils.formataddr((SENDERNAME, SENDER))
msg['To'] = RECIPIENT
# Comment or delete the next line if you are not using a configuration set
#msg.add_header('X-SES-CONFIGURATION-SET',CONFIGURATION_SET)

# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(BODY_TEXT, 'plain')
part2 = MIMEText(BODY_HTML, 'html')

# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)

# Try to send the message.
if 1: #try:  
    server = smtplib.SMTP(HOST, PORT)
    server.ehlo()
    server.starttls()
    #stmplib docs recommend calling ehlo() before & after starttls()
    server.ehlo()
    server.login(USERNAME_SMTP, PASSWORD_SMTP)
    server.sendmail(SENDER, RECIPIENT, msg.as_string())
    server.close()
# Display an error message if something goes wrong.
"""
except Exception as e:
    print ("Error: ", e)
else:
    print ("Email sent!")
"""

EDIT : It seems that SMTP is not compatible with AppEngine: Can Google App Engine use a third party SMTP server?

As you mention, there are some problems when you try to use an external SMTP service using sockets. My advice is to use the Amazon SES API as an alternative.

The request syntax for python to send an email will be like this

response = client.send_email(
Source='string',
Destination={
    'ToAddresses': [
        'string',
    ],
    'CcAddresses': [
        'string',
    ],
    'BccAddresses': [
        'string',
    ]
},
Message={
    'Subject': {
        'Data': 'string',
        'Charset': 'string'
    },
    'Body': {
        'Text': {
            'Data': 'string',
            'Charset': 'string'
        },
        'Html': {
            'Data': 'string',
            'Charset': 'string'
        }
    }
},
ReplyToAddresses=[
    'string',
],
ReturnPath='string',
SourceArn='string',
ReturnPathArn='string',
Tags=[
    {
        'Name': 'string',
        'Value': 'string'
    },
],
ConfigurationSetName='string'
)

An example for sending a simple email:

import boto3

client = boto3.client(
    'ses',
    region_name=region,
    aws_access_key_id='aws_access_key_string',
    aws_secret_access_key='aws_secret_key_string'
)

    response = client.send_email(
    Destination={
        'ToAddresses': ['recipient1@domain.com', 'recipient2@domain.com],
    },
    Message={
        'Body': {
            'Text': {
                'Charset': 'UTF-8',
                'Data': 'email body string',
            },
        },
        'Subject': {
            'Charset': 'UTF-8',
            'Data': 'email subject string',
        },
    },
    Source='sender.email@domain.com',
)

Here's more methods you can use for the SES API.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM