Email Service

The email service: the platform’s outgoing email.

Email does not depend on a cloud: Smarter sends it with SMTP, to any SMTP server, e.g. AWS Simple Email Service’s. So EmailService is implemented by SMTPEmailService, for every cloud provider, and an email API, e.g. a cloud’s, would be another implementation.

The platform uses it through smarter.apps.infrastructure.services.infrastructure .email. Tests replace it with configure_email(), e.g. with InMemoryEmailService.

from smarter.apps.infrastructure.services import infrastructure

infrastructure.email.send_email(subject="Welcome!", body="<p>Hello</p>", to="user@example.com", html=True)
class smarter.apps.infrastructure.services.email.EmailService(provider_name, *args, **kwargs)[source]

Bases: InfrastructureService

The platform’s outgoing email.

static admin_bcc(recipients)[source]

The blind copy to the platform’s admin, smarter_settings.email_admin.

Parameters:

recipients (list[str]) – The email’s recipients, who need no copy.

Return type:

list[str]

Returns:

The admin’s address, or nothing if there is no valid admin address, or the admin is a recipient.

error_class

alias of EmailServiceError

message(subject, body, to, html=False, from_email=None)[source]

Return a message, from smarter_settings.smtp_from_email unless from_email is given.

It has no Bcc header: blind copies are added to the envelope by _deliver().

Return type:

MIMEMultipart

send_email(subject, body, to, html=False, from_email=None, quiet=False, bcc_admin=True)[source]

Send an email.

Failures are logged, and announced with email_failed, rather than raised, so that email never breaks the request that sends it.

Parameters:
  • subject (str) – The subject.

  • body (str) – The body, HTML if html is True.

  • to (Union[str, List[str]]) – The recipient, or recipients. Invalid addresses are dropped.

  • html (bool) – True if the body is HTML.

  • from_email (Optional[str]) – The sender, by default smarter_settings.smtp_from_email.

  • quiet (bool) – True to only log what would have been sent.

  • bcc_admin (bool) – Send a blind copy to the platform’s admin, smarter_settings.email_admin. Pass False for an email that carries a secret, e.g. a password reset link, which only its recipient may see.

Return type:

bool

Returns:

True if the email was sent.

service_name: str = 'email'

The name of the service in signals and logs, see InfrastructureServiceNames.

static validate_mail_list(emails, quiet=False)[source]

Return the valid email addresses of a list.

Parameters:
  • emails (Union[str, List[str]]) – An email address, or a list of them.

  • quiet (bool) – True to not log invalid addresses.

Return type:

Optional[List[str]]

Returns:

The valid addresses, or None if there are none.

class smarter.apps.infrastructure.services.email.InMemoryEmailService(ready=True, **kwargs)[source]

Bases: EmailService

Email that is kept in outbox, for tests and local development.

Parameters:

ready (bool) – Whether the service is ready.

__init__(ready=True, **kwargs)[source]
fail: str | None

Set to make delivery fail with this error.

outbox: list[SentEmail]
property ready: bool

Whether the service is authenticated and connected, i.e. it can be used.

class smarter.apps.infrastructure.services.email.SMTPEmailService(allow_in_tests=False, smtp_class=<class 'smtplib.SMTP'>, **kwargs)[source]

Bases: EmailService

Email, with SMTP, configured by the smtp_* settings of smarter_settings.

In the unit tests, nothing is sent, unless allow_in_tests is True, so that tests never email real people.

Parameters:
  • allow_in_tests (bool) – Send email in the unit tests.

  • smtp_class (Callable[..., SMTP]) – The SMTP client class, e.g. a fake.

__init__(allow_in_tests=False, smtp_class=<class 'smtplib.SMTP'>, **kwargs)[source]
property ready: bool

Whether the service is authenticated and connected, i.e. it can be used.

class smarter.apps.infrastructure.services.email.SentEmail(subject, sender, recipients, bcc=<factory>, body='', headers=<factory>)[source]

Bases: object

An email that InMemoryEmailService sent.

__init__(subject, sender, recipients, bcc=<factory>, body='', headers=<factory>)
bcc: list[str]
body: str = ''
headers: dict[str, str]
recipients: list[str]
sender: str
subject: str
smarter.apps.infrastructure.services.email.configure_email(factory)[source]

Set the factory of the email service that get_email() returns.

Parameters:

factory (Optional[Callable[[], EmailService]]) – Returns the service, or None to restore the default, SMTPEmailService.

Return type:

None

smarter.apps.infrastructure.services.email.get_email()[source]

Return the email service, which is created once.

Return type:

EmailService