AWS Lambda错误没有名为'StringIO'的模块或没有名为'StringIO'的模块

问题描述 投票:0回答:2

我尝试使用AWS Lambda进行大量电子邮件发送,我们使用的代码如下链接:https://aws.amazon.com/cn/premiumsupport/knowledge-center/mass-email-ses-lambda/

from __future__ import print_function

import StringIO
import csv
import json
import os
import urllib
import zlib

from time import strftime, gmtime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

import boto3
import botocore
import concurrent.futures

__author__ = 'Said Ali Samed'
__date__ = '10/04/2016'
__version__ = '1.0'

# Get Lambda environment variables
region = os.environ['us-east-1']
max_threads = os.environ['10']
text_message_file = os.environ['email_body.txt']
html_message_file = os.environ['email_body.html']

# Initialize clients
s3 = boto3.client('s3', region_name=region)
ses = boto3.client('ses', region_name=region)
send_errors = []
mime_message_text = ''
mime_message_html = ''


def current_time():
    return strftime("%Y-%m-%d %H:%M:%S UTC", gmtime())


def mime_email(subject, from_address, to_address, text_message=None, html_message=None):
    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = from_address
    msg['To'] = to_address
    if text_message:
        msg.attach(MIMEText(text_message, 'plain'))
    if html_message:
        msg.attach(MIMEText(html_message, 'html'))

    return msg.as_string()


def send_mail(from_address, to_address, message):
    global send_errors
    try:
        response = ses.send_raw_email(
            Source=from_address,
            Destinations=[
                to_address,
            ],
            RawMessage={
                'Data': message
            }
        )
        if not isinstance(response, dict):  # log failed requests only
            send_errors.append('%s, %s, %s' % (current_time(), to_address, response))
    except botocore.exceptions.ClientError as e:
        send_errors.append('%s, %s, %s, %s' %
                           (current_time(),
                               to_address,
                               ', '.join("%s=%r" % (k, v) for (k, v) in e.response['ResponseMetadata'].iteritems()),
                               e.message))


def lambda_handler(event, context):
    global send_errors
    global mime_message_text
    global mime_message_html
    try:
        # Read the uploaded csv file from the bucket into python dictionary list
        bucket = event['Records'][0]['s3']['bucket']['name']
        key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
        response = s3.get_object(Bucket=bucket, Key=key)
        body = zlib.decompress(response['Body'].read(), 16+zlib.MAX_WBITS)
        reader = csv.DictReader(StringIO.StringIO(body),
                                fieldnames=['from_address', 'to_address', 'subject', 'message'])

        # Read the message files
        try:
            response = s3.get_object(Bucket=bucket, Key=text_message_file)
            mime_message_text = response['Body'].read()
        except:
            mime_message_text = None
            print('Failed to read text message file. Did you upload %s?' % text_message_file)
        try:
            response = s3.get_object(Bucket=bucket, Key=html_message_file)
            mime_message_html = response['Body'].read()
        except:
            mime_message_html = None
            print('Failed to read html message file. Did you upload %s?' % html_message_file)

        if not mime_message_text and not mime_message_html:
            raise ValueError('Cannot continue without a text or html message file.')

        # Send in parallel using several threads
        e = concurrent.futures.ThreadPoolExecutor(max_workers=max_threads)
        for row in reader:
            from_address = row['from_address'].strip()
            to_address = row['to_address'].strip()
            subject = row['subject'].strip()
            message = mime_email(subject, from_address, to_address, mime_message_text, mime_message_html)
            e.submit(send_mail, from_address, to_address, message)
        e.shutdown()
    except Exception as e:
        print(e.message + ' Aborting...')
        raise e

    print('Send email complete.')

    # Remove the uploaded csv file
    try:
        response = s3.delete_object(Bucket=bucket, Key=key)
        if 'ResponseMetadata' in response.keys() and response['ResponseMetadata']['HTTPStatusCode'] == 204:
            print('Removed s3://%s/%s' % (bucket, key))
    except Exception as e:
        print(e)

    # Upload errors if any to S3
    if len(send_errors) > 0:
        try:
            result_data = '\n'.join(send_errors)
            logfile_key = key.replace('.csv.gz', '') + '_error.log'
            response = s3.put_object(Bucket=bucket, Key=logfile_key, Body=result_data)
            if 'ResponseMetadata' in response.keys() and response['ResponseMetadata']['HTTPStatusCode'] == 200:
                print('Send email errors saved in s3://%s/%s' % (bucket, logfile_key))
        except Exception as e:
            print(e)
            raise e
        # Reset publish error log
        send_errors = []


if __name__ == "__main__":
    json_content = json.loads(open('event.json', 'r').read())
    lambda_handler(json_content, None)

但是当我选择python 2.7时它有问题。错误是

module initialization error 'us-east-1'

当我选择python 3.6时,错误是

Unable to import module 'lambda_function': No module named 'StringIO'

谁能告诉我它是什么问题?

amazon-web-services aws-lambda amazon-ses
2个回答
0
投票

请按照step 4 of the article中的说明设置环境变量:“配置适合您的使用场景的Lambda环境变量。例如,以下变量对于给定的用例有效:REGION = us-east-1,MAX_THREADS = 10,TEXT_MESSAGE_FILE = email_body.txt,HTML_MESSAGE_FILE = email_body.html。“

所做的(根据问题中提供的代码)是用它们的值替换环境变量的名称,这意味着python正在寻找例如'us-east-1'环境变量不存在......

这是原始代码

# Get Lambda environment variables
region = os.environ['REGION']
max_threads = os.environ['MAX_THREADS']
text_message_file = os.environ['TEXT_MESSAGE_FILE']
html_message_file = os.environ['HTML_MESSAGE_FILE']

您还可以对值进行硬编码,如下所示:

# Get Lambda environment variables
region = 'us-east-1'
max_threads = '10'
text_message_file = 'email_body.txt'
html_message_file = 'email_body.html'

但我建议改为设置环境变量(并使用article author提供的脚本版本)。在Lambda中设置环境变量时,see this article :)


0
投票

从Python v3,StringIO module has gone。而是导入io模块并使用io.StringIO。

v27版本的问题可能是以下语句失败:

region = os.environ['us-east-1']

如果us-east-1不是可用的环境变量,这将导致KeyError。而是使用AWS_REGIONAWS_DEFAULT_REGION。查看Lambda environment variables的完整列表。

© www.soinside.com 2019 - 2024. All rights reserved.