Enviando e-mail

Although Python provides a mail sending interface via the smtplib module, Django provides a couple of light wrappers over it. These wrappers are provided to make sending email extra quick, to help test email sending during development, and to provide support for platforms that can’t use SMTP.

O código pode ser encontrado no módulo django.core.mail.

Exemplo rápido

Em duas linhas:

from django.core.mail import send_mail

send_mail(
    "Subject here",
    "Here is the message.",
    "[email protected]",
    ["[email protected]"],
    fail_silently=False,
)

O email é enviado usando o host e porta SMTP especificados em EMAIL_HOST e EMAIL_PORT. As configurações EMAIL_HOST_USER e EMAIL_HOST_PASSWORD, se definidas, são usadas para autenticar no servidor SMTP, e as configurações EMAIL_USE_TLS e EMAIL_USE_SSL controlam se uma conexão segura deve ou não ser usada.

Nota

O conjunto de caracteres do email enviado com django.core.mail será definido como sendo o valor da configuração DEFAULT_CHARSET.

send_mail()

send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)

In most cases, you can send email using django.core.mail.send_mail().

Os parâmetros subject, message, from_email e recipient_list devem ser informados.

  • subject: uma string.
  • message: uma string.
  • from_email: A string. If None, Django will use the value of the DEFAULT_FROM_EMAIL setting.
  • recipient_list: uma lista de strings, onde cada item representa um endereço de email. Cada membro de recipient_list verá os outros recipientes no campo “To:” da mensagem de email.
  • fail_silently: A boolean. When it’s False, send_mail() will raise an smtplib.SMTPException if an error occurs. See the smtplib docs for a list of possible exceptions, all of which are subclasses of SMTPException.
  • auth_user: O username opcional para ser usado na autenticação do servidor SMTP. Se isso não for fornecido, o Django irá usar o valor da configuração EMAIL_HOST_USER.
  • auth_password: A senha opcional para ser usada na autenticação no servidor SMTP. Se isso não for fornecido, o Django irá usar o valor da configuração EMAIL_HOST_PASSWORD.
  • connection: O backend opcional a ser usado para o de email. Se indefinido, uma instância do backend default será usada. Veja a documentação em Email backends para mais detalhes.
  • html_message: Se html_message for fornecido, o email resultante será um multipart/alternative email com message sendo do tipo text/plain e html_message sendo do tipo text/html.

O valor retornado será o número de mensagens entregues com sucesso (o que pode ser 0 ou 1 já que ele só pode enviar uma mensagem).

send_mass_mail()

send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None)

django.core.mail.send_mass_mail() foi pensado para manipular envios massivos de email.

datatuple é uma tupla na qual cada elemento possui o seguinte formato:

(subject, message, from_email, recipient_list)

fail_silently, auth_user e auth_password possuem as mesmas funções do método send_mail().

Cada elemento separadamente da datatuple resulta em uma mensagem em separado. Como no método send_mail(), destinatários na mesma lista recipient_list serão capazes de visualizar os outros endereços no campo “To:” das mensagens de email.

Por exemplo, o código abaixo enviaria duas mensagens diferentes para dois conjuntos diferentes de destinatários; porém, somente uma conexão para o servidor de email seria aberta:

message1 = (
    "Subject here",
    "Here is the message",
    "[email protected]",
    ["[email protected]", "[email protected]"],
)
message2 = (
    "Another Subject",
    "Here is another message",
    "[email protected]",
    ["[email protected]"],
)
send_mass_mail((message1, message2), fail_silently=False)

O valor de retorno será o número de mensagens entregues com sucesso.

send_mass_mail() vs. send_mail()

A principal diferença entre os métodos send_mass_mail() e send_mail() é que o método send_mail() abre uma nova conexão para o servidor de email toda vez que é executado, enquanto que o método send_mass_mail() utiliza uma única conexão para todas as suas mensagens. Isso faz com que o método send_mass_mail() seja um pouco mais eficiente.

mail_admins()

mail_admins(subject, message, fail_silently=False, connection=None, html_message=None)

django.core.mail.mail_admins() é um atalho para o envio de email para os admins do site, conforme definido na configuração ADMINS setting.

mail_admins() prefixa o conteúdo com o valor da configuração EMAIL_SUBJECT_PREFIX, que é "[Django] " por padrão.

O cabeçalho “From:” do email será o valor da configuração SERVER_EMAIL.

Esse método existe por conveniência e legibilidade.

Se html_message é fornecido, o email resultante será um email do tipo multipart/alternative com message sendo do tipo text/plain e html_message sendo do tipo text/html.

mail_managers()

mail_managers(subject, message, fail_silently=False, connection=None, html_message=None)

django.core.mail.mail_managers() é parecido com mail_admins(), exceto pelo fato de que ele envia um email para os mantenedores do site, conforme definido na configuração MANAGERS.

Exemplos

Isso envia um único email para john@example.com e jane@example.com, com ambos aparecendo no campo “To:”:

send_mail(
    "Subject",
    "Message.",
    "[email protected]",
    ["[email protected]", "[email protected]"],
)

Isso envia uma mensagem para john@example.com e jane@example.com, com ambos recebendo um email em separado:

datatuple = (
    ("Subject", "Message.", "[email protected]", ["[email protected]"]),
    ("Subject", "Message.", "[email protected]", ["[email protected]"]),
)
send_mass_mail(datatuple)

Prevenindo injeção de cabeçalhos

injeção de cabeçalhos é uma vulnerabilidade de segurança onde um atacante insere cabeçalhos extras no email para controlar os campos “To:” e “From:” em mensagens de email geradas pelos seus scripts.

As funções de email do Django descritas acima protegem contra injeção de cabeçalhos proibindo novas linhas nos valores do cabeçalho. Se qualquer campo subject, from_email ou recipient_list contém uma nova linha (seja no estilo Unix, Windows ou Mac), a função de email (por exemplo, o método BadHeaderError`() (uma subclasse de ValueError) e, por tanto, não envia o email. É sua responsabilidade validar todos os dados do email antes de passá-los para as funções de email.

If a message contains headers at the start of the string, the headers will be printed as the first bit of the email message.

Segue uma view de exemplo que recebe subject, message e from_email de uma requisição POST, envia esses dados para admin@example.com e redireciona para “/contact/thanks/” no final:

from django.core.mail import BadHeaderError, send_mail
from django.http import HttpResponse, HttpResponseRedirect


def send_email(request):
    subject = request.POST.get("subject", "")
    message = request.POST.get("message", "")
    from_email = request.POST.get("from_email", "")
    if subject and message and from_email:
        try:
            send_mail(subject, message, from_email, ["[email protected]"])
        except BadHeaderError:
            return HttpResponse("Invalid header found.")
        return HttpResponseRedirect("/contact/thanks/")
    else:
        # In reality we'd use a form class
        # to get proper validation errors.
        return HttpResponse("Make sure all fields are entered and valid.")

A classe EmailMessage

As funções do Django send_mail() e send_mass_mail() são na verdade pequenos wrappers que fazem uso da classe EmailMessage.

Nem todas as funcionalidades da classe EmailMessage estão disponíveis através das funções send_mail() e funções wrapper relacionadas. Se você quiser usar recursos avançados, tais como destinatários BCC’ed, anexar de arquivos, ou email de múltiplas partes, você terá que criar instâncias da classe EmailMessage diretamente.

Nota

Esse é um recurso de design. A função send_mail() e funções relacionadas foram originalmente a única interface que o Django fornecia. Porém, a lista de parâmetros que elas aceitavam foi aos poucos crescendo com o passar do tempo. Fez sentido mudar para um design mais orientado a objetos para mensagens de email e manter as funções originais apenas para manter compatibilidade com versões anteriores.

A classe EmailMessage é responsável por criar a mensagem de email em si. O email backend é depois responsável pelo envio da mensagem.

For convenience, EmailMessage provides a send() method for sending a single email. If you need to send multiple messages, the email backend API provides an alternative.

Objetos EmailMessage

class EmailMessage

A classe EmailMessage é inicializada com os seguintes parâmetros (na seguinte ordem, se argumentos posicionais são usados). Todos os parâmetros são opcionais e podem ser informados a qualquer momento anterior a chamada do método send().

  • subject: A linha de assunto do email.
  • body: O corpo do texto. Deve ser uma mensagem em texto simples.
  • from_email: The sender’s address. Both fred@example.com and "Fred" <fred@example.com> forms are legal. If omitted, the DEFAULT_FROM_EMAIL setting is used.
  • to: Uma lista de tuplas de endereços dos destinatários.
  • bcc: uma lista de tuplas de endereços usados no cabeçalho “Bcc” ao enviar o email.
  • connection: uma instância do email backend. Utilize esse parâmetro se você quiser usar a mesma conexão para múltiplas mensagens. Se omitido, uma nova conexão é criada quando a função send() é chamada.
  • attachments: A list of attachments to put on the message. These can be either MIMEBase instances, or (filename, content, mimetype) triples.
  • headers: um dicionário de cabeçalhos extras para colocar na mensagem. As chaves são os nomes dos cabeçalhos, valores são os valores do cabeçalho. É responsabilidade de quem chama garantir que os nomes e valores dos cabeçalhos estão no formato correto para uma mensagem de email. O atributo correspondente é extra_headers.
  • cc: uma lista ou tupla de endereços de destinatários usados no cabeçalho “Cc” no envio do email.
  • reply_to: uma lista ou tupla de endereços de destinatários usados no cabeçalho “Reply-To” no envio do email.

Por exemplo:

from django.core.mail import EmailMessage

email = EmailMessage(
    "Hello",
    "Body goes here",
    "[email protected]",
    ["[email protected]", "[email protected]"],
    ["[email protected]"],
    reply_to=["[email protected]"],
    headers={"Message-ID": "foo"},
)

A classe possui os seguintes métodos:

  • send(fail_silently=False) sends the message. If a connection was specified when the email was constructed, that connection will be used. Otherwise, an instance of the default backend will be instantiated and used. If the keyword argument fail_silently is True, exceptions raised while sending the message will be quashed. An empty list of recipients will not raise an exception. It will return 1 if the message was sent successfully, otherwise 0.

  • message() constructs a django.core.mail.SafeMIMEText object (a subclass of Python’s MIMEText class) or a django.core.mail.SafeMIMEMultipart object holding the message to be sent. If you ever need to extend the EmailMessage class, you’ll probably want to override this method to put the content you want into the MIME object.

  • recipients() retorna uma lista de todos os destinatários da mensagem, independentemente de eles serem gravados nos atributos to, cc ou bcc. Esse é outro método que você pode precisar sobrescrever ao fazer uma subclasse, porque o servidor SMTP precisa saber toda a lista de destinatários quando a mensagem é enviada. Se você adicionar outra forma de especificar os destinatários em sua classe, eles precisam ser retornados desse método também.

  • attach() cria um novo anexo de arquivo e adiciona ele a mensagem. Existem duas maneiras de chamar attach():

    • You can pass it a single argument that is a MIMEBase instance. This will be inserted directly into the resulting message.

    • Alternativamente, você pode passar ao attach() três argumentos: filename, content e mimetype. filename é o nome do anexo de arquivo que será exibido no email, content é a data que estará contida dentro do anexo e mimetype é o tipo MIME opcional para o anexo. Se você omitir mimetype, o tipo MIME será inferido do nome do anexo de arquivo.

      Por exemplo:

      message.attach("design.png", img_data, "image/png")
      

      If you specify a mimetype of message/rfc822, it will also accept django.core.mail.EmailMessage and email.message.Message.

      For a mimetype starting with text/, content is expected to be a string. Binary data will be decoded using UTF-8, and if that fails, the MIME type will be changed to application/octet-stream and the data will be attached unchanged.

      In addition, message/rfc822 attachments will no longer be base64-encoded in violation of RFC 2046#section-5.2.1, which can cause issues with displaying the attachments in Evolution and Thunderbird.

  • attach_file() creates a new attachment using a file from your filesystem. Call it with the path of the file to attach and, optionally, the MIME type to use for the attachment. If the MIME type is omitted, it will be guessed from the filename. You can use it like this:

    message.attach_file("/images/weather_map.png")
    

    For MIME types starting with text/, binary data is handled as in attach().

Enviando tipos de conteúdo alternativos

Pode ser útil incluir múltiplas versões de conteúdo em um email; o exemplo clássico é enviar tanto a versão em texto simples quanto a versão em HTML de uma mensagem. Com a biblioteca de email do Django, você pode fazer isso usando a classe EmailMultiAlternatives. Essa subclasse de EmailMessage possui um método attach_alternative() para inclusão de versões extras de corpos de mensagens no email. Todos os outros métodos (incluindo a inicialização da classe) são herdados diretamente da classe EmailMessage.

Para enviar uma combinação de texto simples e HTML, você pode escrever:

from django.core.mail import EmailMultiAlternatives

subject, from_email, to = "hello", "[email protected]", "[email protected]"
text_content = "This is an important message."
html_content = "<p>This is an <strong>important</strong> message.</p>"
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()

Por padrão, o tipo MIME de um parâmetro body em uma classe EmailMessage é "text/plain". É uma boa prática deixar assim, porque isso garante que qualquer destinatário esteja apto a ler o email, independentemente do cliente de email. Porém, se você estiver confiante que seus destinatários podem manipular um tipo alternativo de conteúdi, você pode usar o atributo content_subtype da classe EmailMessage para mudar o principal tipo de conteúdo. O principal tipo sempre será “text”``, mas você pode mudar o subtipo. Por exemplo:

msg = EmailMessage(subject, html_content, from_email, [to])
msg.content_subtype = "html"  # Main content is now text/html
msg.send()

Backends de email

O envio de email em si é manipulado pelo email backend.

A classe do email backend tem os métodos a seguir:

  • open() instancia uma conexão de longa duração para envio de email.
  • close() fecha a conexão atual de envio de email.
  • send_messages(email_messages) sends a list of EmailMessage objects. If the connection is not open, this call will implicitly open the connection, and close the connection afterward. If the connection is already open, it will be left open after mail has been sent.

Ela também pode ser usada como em um gerenciador de contexto, que irá automaticamente chamar open() e close() conforme necessário:

from django.core import mail

with mail.get_connection() as connection:
    mail.EmailMessage(
        subject1,
        body1,
        from1,
        [to1],
        connection=connection,
    ).send()
    mail.EmailMessage(
        subject2,
        body2,
        from2,
        [to2],
        connection=connection,
    ).send()

Obtendo uma instância de um email backend

A funçção get_connection() em django.core.mail retorna uma instância do email backend que você pode utilizar.

get_connection(backend=None, fail_silently=False, *args, **kwargs)

Por padrão, uma chamada para get_connection() irá retornar uma instância do email backend definido em EMAIL_BACKEND. Se você especificar o argumento backend, uma instância desse backend será criada.

O argumento fail_silently controla como o backend deve manipular erros. Se fail_silently é True, exceções durante o processo de envio de email serão ignoradas silenciosamente.

Todos os outros argumentos são passados diretamente para o construtor do email backend.

O Django é fornecido com vários backends de envio de email. Com exceção do backend SMTP (que é o padrão), esses backends só são úteis durante testes e desenvolvimento. Se você tiver requisitos especiais de envio de email, você pode escrever o seu próprio email backend.

SMTP backend

class backends.smtp.EmailBackend(host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, use_ssl=None, timeout=None, ssl_keyfile=None, ssl_certfile=None, **kwargs)

Este é o backend padrão. Email será enviado através de um servidor SMTP.

O valor de cada argumento é obtido da respectiva configuração se o argumento for None:

O backend SMTP é a configuração padrão herdada do Django. Se você quiser especificá-la explicitamente, adicione o seguinte as suas configurações:

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"

Se não definido, o timeout padrão será o fornecido pela função socket.getdefaulttimeout(), que por padrão é None (sem limite de tempo).

Console backend

Ao invés de enviar emails reais o console backend escreve esses emails que poderiam ser enviados na saída padrão. Por padrão, o console backend direciona para stdout. Você pode usar diferentes objetos fornecendo o argumento nomeado stream ao construir a conexão.

Para especificar esse backend, coloque o seguinte nas suas configurações:

EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"

Esse backend não é intencionado para uso em produção – ele é fornecido como uma conveniência que pode ser usado durante o desenvolvimento.

File backend

O file backend escreve emails em um arquivo. Um novo arquivo é criado para cada nova sessão que é aberto no backend. O diretório para o qual os arquivos são escritos ou é obitdo da configuração EMAIL_FILE_PATH ou do argumento nomeado file_path ao criar uma conexão com o método get_connection().

Para especificar esse backend, coloque o seguinte nas suas configurações:

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = "/tmp/app-messages"  # change this to a proper location

Esse backend não é intencionado para uso em produção – ele é fornecido como uma conveniência que pode ser usado durante o desenvolvimento.

In-memory backend

O 'locmem' backend armazena mensagens em um atributo especial do módulo django.core.mail. O atributo outbox é criado quando a primeira mensagem é enviada. É uma lista com uma instância da classe EmailMessage para cada mensagem que possa ser enviada.

Para especificar esse backend, coloque o seguinte nas suas configurações:

EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"

Esse backend não é intencionado para uso em produção – ele é fornecido como uma conveniência que pode ser usado durante o desenvolvimento e teste.

Django’s test runner automatically uses this backend for testing.

Dummy backend

Como o nome sugere o dummy backend não faz nada com suas mensagens. Para definir esse backend, coloque o seguinte em suas configurações:

EMAIL_BACKEND = "django.core.mail.backends.dummy.EmailBackend"

Esse backend não é intencionado para uso em produção – ele é fornecido como uma conveniência que pode ser usado durante o desenvolvimento.

Definindo um email backend customizado

Se você precisa mudar como os emails são enviados você pode escrever o seu próprio email backend. A configuração EMAIL_BACKEND em seu arquivo de configurações é então o caminho Python do import para a sua classe backend.

Bckends de email customizados devem ser subclasses de BaseEmailBackend que está localizada no módulo django.core.mail.backends.base. Um backend de email customizado deve implementar o método send_messages(email_messages). Esse método recebe uma lista de instâncias da classe EmailMessage e retorna o número de mensagens entregues com sucesso. Se o seu backend possui qualquer conceito de sessão persistente ou conexão, você também deve implementar os métodos open() e close(). Consulte smtp.EmailBackend para uma implementação de referência.

Enviando mútiplos emails

Estabelecer e fechar uma conexão SMTP (ou qualquer outra conexão de rede, nesse caso) é um processo custoso. Se você tem muitos emails para enviar, faz sentido reutilizar uma conexão SMTP, ao invés de criar e destruir uma conexão toda vez que você desejar enviar um email.

Existem duas maneiras de dizer a um email backend para reutilizar uma conexão.

Primeiramente, você pode usar o método send_messages(). send_messages() recebe uma lista de instâncias da classe EmailMessage (ou de subclasses), e envia todas elas usando uma única conexão.

Por exemplo, se você tiver uma função chamada get_notification_email() que retorna uma lista de objetos da classe EmailMessage representando algum email periódico que você gostaria de enviar, voê pode enviá-los usando uma única chamada para send_messages:

from django.core import mail

connection = mail.get_connection()  # Use default email connection
messages = get_notification_email()
connection.send_messages(messages)

Neste exemplo, a chamada send_messages() abre uma conexão no backend, envia a lista de mensagens, e então fecha a conexão novamente.

A segunda abordagem é usar os métodos open() e close() no backend de email para manualmente controlar a conexão. send_messages() não irá abrir ou fechar manualmente a conexão se ela já estiver aberta, se você manualmente abrir a conexão, você pode controlar quando ela será fechada. Por exemplo:

from django.core import mail

connection = mail.get_connection()

# Manually open the connection
connection.open()

# Construct an email message that uses the connection
email1 = mail.EmailMessage(
    "Hello",
    "Body goes here",
    "[email protected]",
    ["[email protected]"],
    connection=connection,
)
email1.send()  # Send the email

# Construct two more messages
email2 = mail.EmailMessage(
    "Hello",
    "Body goes here",
    "[email protected]",
    ["[email protected]"],
)
email3 = mail.EmailMessage(
    "Hello",
    "Body goes here",
    "[email protected]",
    ["[email protected]"],
)

# Send the two emails in a single call -
connection.send_messages([email2, email3])
# The connection was already open so send_messages() doesn't close it.
# We need to manually close the connection.
connection.close()

Configurando o email para o desenvolvimento

Existem momentos em que você não quer que o Django envie quaisquer emails. Por exemplo, enquanto estiver desenvolvendo um website, você provavelmente não quer enviar milhares de emails – mas você pode querer validar que esses email serão enviados para as pessoas certas nas condições certas, e que esses emails irão conter o conteúdo correto.

The easiest way to configure email for local development is to use the console email backend. This backend redirects all email to stdout, allowing you to inspect the content of mail.

O file email backend também pode ser útil durante o desenvolvimento – esse backend despeja o conteúdo de todoas as conexões SMTP para um arquivo que pode ser inspecionado quando você desejar.

Another approach is to use a “dumb” SMTP server that receives the emails locally and displays them to the terminal, but does not actually send anything. The aiosmtpd package provides a way to accomplish this:

python -m pip install aiosmtpd

python -m aiosmtpd -n -l localhost:8025

This command will start a minimal SMTP server listening on port 8025 of localhost. This server prints to standard output all email headers and the email body. You then only need to set the EMAIL_HOST and EMAIL_PORT accordingly. For a more detailed discussion of SMTP server options, see the documentation of the aiosmtpd module.

Para mais informações sobre testes unitários no envio de emails em suas aplicações, veja a seção Serviços de E-mail sobre testes da documentação.

Back to Top