Cookiecutter - Django: Anymail[SES] boto3 区域错误

Cookiecutter - Django: Anymail[SES] boto3 region error

我正在尝试向 AWS(EC2) 部署一个 Cookiecutter Django 项目。 具有此凭证的 AWS 用户具有完整的 S3、SES 和 SNS 策略。 EC2 服务器还有一个具有完整 SES/S3 策略的角色。

在 envs 的生产文件中,我设置了这样的密钥。

DJANGO_AWS_ACCESS_KEY_ID=xxxxxxxxx
DJANGO_AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
DJANGO_AWS_STORAGE_BUCKET_NAME=xxxxxxxxxx 

在我的设置中

AWS_S3_REGION_NAME = env("DJANGO_AWS_S3_REGION_NAME", default=None)
AWS_ACCESS_KEY_ID = env("DJANGO_AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = env("DJANGO_AWS_SECRET_ACCESS_KEY")
AWS_STORAGE_BUCKET_NAME = env("DJANGO_AWS_STORAGE_BUCKET_NAME")
EMAIL_BACKEND = "anymail.backends.amazon_ses.EmailBackend"
ANYMAIL = {}

一切都很好,直到项目尝试使用 SES 发送电子邮件并且它因以下错误而崩溃。

到目前为止我已经尝试过:

这是错误。 'NoneType' object has no attribute 'send_raw_email' 的第二部分在这之后重复了很多。

django_1    | [2021-08-13 13:58:14 +0000] [12] [ERROR] Error handling request /accounts/signup/
django_1    | Traceback (most recent call last):
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
django_1    |     response = get_response(request)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
django_1    |     response = wrapped_callback(request, *callback_args, **callback_kwargs)
django_1    |   File "/usr/local/lib/python3.9/contextlib.py", line 79, in inner
django_1    |     return func(*args, **kwds)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
django_1    |     return self.dispatch(request, *args, **kwargs)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/utils/decorators.py", line 43, in _wrapper
django_1    |     return bound_method(*args, **kwargs)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/views/decorators/debug.py", line 89, in sensitive_post_parameters_wrapper
django_1    |     return view(request, *args, **kwargs)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/views.py", line 230, in dispatch
django_1    |     return super(SignupView, self).dispatch(request, *args, **kwargs)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/views.py", line 74, in dispatch
django_1    |     response = super(RedirectAuthenticatedUserMixin, self).dispatch(
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/views.py", line 204, in dispatch
django_1    |     return super(CloseableSignupMixin, self).dispatch(request, *args, **kwargs)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/views/generic/base.py", line 98, in dispatch
django_1    |     return handler(request, *args, **kwargs)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/views.py", line 102, in post
django_1    |     response = self.form_valid(form)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/views.py", line 248, in form_valid
django_1    |     return complete_signup(
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/utils.py", line 209, in complete_signup
django_1    |     return perform_login(
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/utils.py", line 175, in perform_login
django_1    |     send_email_confirmation(request, user, signup=signup, email=email)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/utils.py", line 346, in send_email_confirmation
django_1    |     email_address.send_confirmation(request, signup=signup)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/models.py", line 62, in send_confirmation
django_1    |     confirmation.send(request, signup=signup)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/models.py", line 169, in send
django_1    |     get_adapter(request).send_confirmation_mail(request, self, signup)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/adapter.py", line 464, in send_confirmation_mail
django_1    |     self.send_mail(email_template, emailconfirmation.email_address.email, ctx)
django_1    |   File "/usr/local/lib/python3.9/site-packages/allauth/account/adapter.py", line 136, in send_mail
django_1    |     msg.send()
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/core/mail/message.py", line 284, in send
django_1    |     return self.get_connection(fail_silently).send_messages([self])
django_1    |   File "/usr/local/lib/python3.9/site-packages/anymail/backends/base.py", line 89, in send_messages
django_1    |     created_session = self.open()
django_1    |   File "/usr/local/lib/python3.9/site-packages/anymail/backends/amazon_ses.py", line 44, in open
django_1    |     self.client = boto3.session.Session(**self.session_params).client("ses", **self.client_params)
django_1    |   File "/usr/local/lib/python3.9/site-packages/boto3/session.py", line 258, in client
django_1    |     return self._session.create_client(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/session.py", line 847, in create_client
django_1    |     client = client_creator.create_client(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/client.py", line 86, in create_client
django_1    |     client_args = self._get_client_args(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/client.py", line 355, in _get_client_args
django_1    |     return args_creator.get_client_args(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/args.py", line 71, in get_client_args
django_1    |     final_args = self.compute_client_args(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/args.py", line 148, in compute_client_args
django_1    |     endpoint_config = self._compute_endpoint_config(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/args.py", line 220, in _compute_endpoint_config
django_1    |     return self._resolve_endpoint(**resolve_endpoint_kwargs)
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/args.py", line 302, in _resolve_endpoint
django_1    |     return endpoint_bridge.resolve(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/client.py", line 430, in resolve
django_1    |     resolved = self.endpoint_resolver.construct_endpoint(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/regions.py", line 133, in construct_endpoint
django_1    |     result = self._endpoint_for_partition(
django_1    |   File "/usr/local/lib/python3.9/site-packages/botocore/regions.py", line 148, in _endpoint_for_partition
django_1    |     raise NoRegionError()
django_1    | botocore.exceptions.NoRegionError: You must specify a region.
django_1    |
django_1    | During handling of the above exception, another exception occurred:
django_1    |
django_1    | Traceback (most recent call last):
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
django_1    |     response = get_response(request)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/utils/deprecation.py", line 114, in __call__
django_1    |     response = response or self.get_response(request)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 49, in inner
django_1    |     response = response_for_exception(request, exc)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/core/handlers/exception.py", line 104, in response_for_exception
django_1    |     log_response(
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/utils/log.py", line 224, in log_response
django_1    |     getattr(logger, level)(
django_1    |   File "/usr/local/lib/python3.9/logging/__init__.py", line 1475, in error
django_1    |     self._log(ERROR, msg, args, **kwargs)
django_1    |   File "/usr/local/lib/python3.9/logging/__init__.py", line 1589, in _log
django_1    |     self.handle(record)
django_1    |   File "/usr/local/lib/python3.9/logging/__init__.py", line 1599, in handle
django_1    |     self.callHandlers(record)
django_1    |   File "/usr/local/lib/python3.9/logging/__init__.py", line 1661, in callHandlers
django_1    |     hdlr.handle(record)
django_1    |   File "/usr/local/lib/python3.9/logging/__init__.py", line 952, in handle
django_1    |     self.emit(record)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/utils/log.py", line 122, in emit
django_1    |     self.send_mail(subject, message, fail_silently=True, html_message=html_message)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/utils/log.py", line 125, in send_mail
django_1    |     mail.mail_admins(subject, message, *args, connection=self.connection(), **kwargs)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/core/mail/__init__.py", line 104, in mail_admins
django_1    |     mail.send(fail_silently=fail_silently)
django_1    |   File "/usr/local/lib/python3.9/site-packages/django/core/mail/message.py", line 284, in send
django_1    |     return self.get_connection(fail_silently).send_messages([self])
django_1    |   File "/usr/local/lib/python3.9/site-packages/anymail/backends/base.py", line 94, in send_messages
django_1    |     sent = self._send(message)
django_1    |   File "/usr/local/lib/python3.9/site-packages/anymail/backends/base.py", line 124, in _send
django_1    |     response = self.post_to_esp(payload, message)
django_1    |   File "/usr/local/lib/python3.9/site-packages/anymail/backends/amazon_ses.py", line 67, in post_to_esp
django_1    |     response = payload.call_send_api(self.client)
django_1    |   File "/usr/local/lib/python3.9/site-packages/anymail/backends/amazon_ses.py", line 127, in call_send_api
django_1    |     return ses_client.send_raw_email(**self.params)
django_1    | AttributeError: 'NoneType' object has no attribute 'send_raw_email'

如有任何意见,我将不胜感激。我没主意了。 谢谢!

您可能已经发现,问题是 boto3 不知道您要在哪个 AWS 区域中操作:

botocore.exceptions.NoRegionError: You must specify a region.

区域名称来自boto3配置。来自 Anymail's SES docs:

you must make sure boto3 is configured with AWS credentials having the necessary IAM permissions. There are several ways to do this; see Credentials in the Boto docs for options. Usually, an IAM role for EC2 instances, standard Boto environment variables, or a shared AWS credentials file will be appropriate. For more complex cases, use Anymail’s AMAZON_SES_CLIENT_PARAMS setting to customize the Boto session.

看来您可能会尝试混合使用“几种方式”中的一些来提供 boto3 凭据,这可能会造成混淆。

请注意,您的 AWS_* Django 设置不起作用。 boto3 不知道 Django 设置。 Anymail's SES settings docs 描述 Anymail 将哪些 Django 设置传递给 boto3。 (并且 AWS_S3_REGION_NAME 无论如何都不相关,因为 S3 与 SES 不是同一种服务。我猜那些 AWS_* Django 设置可能用于其他一些应用程序,也许是 django-storages。)

如果您想在 settings.py 中专门为 Anymail 提供 AWS 凭证,您可以使用 Anymail 的 AMAZON_SES_CLIENT_PARAMS 设置来实现。例如:

# (Be sure to add DJANGO_AWS_REGION_NAME to your env to use this example)
ANYMAIL = {
    "AMAZON_SES_CLIENT_PARAMS": {
        "aws_access_key_id": env("DJANGO_AWS_ACCESS_KEY_ID"),
        "aws_secret_access_key": env("DJANGO_AWS_SECRET_ACCESS_KEY"),
        "region_name": env("DJANGO_AWS_REGION_NAME"),
    },
}