Sending and responding to email in code

Email is the most popular messaging platform on Earth. We use email to arrange events, to exchange files, and to notify each other when something happens.

You should be able to email your applications too. But to receive email, you need to set up a server somewhere, run an SMTP daemon, and somehow connect that to your code.

We’re here to fix that. Today, we’re delighted to show you the easiest way to build email-driven apps. All you need to do is write a Python function. For example, here’s all the code you need to receive emails and store them in a database:

@anvil.email.handle_message
def incoming_email(msg):
  app_tables.incoming_messages.add_row(
    from_addr=msg.envelope.from_address,
    text=msg.text
  )
  msg.reply(text="Thank you for your message.")

Sending is just as simple:

anvil.email.send(
  to="contact@anvil.works",
  subject="New message",
  text="This is awesome",
  html="This is <b>awesome</b>"
)

Despite its simplicity, it’s also fully featured - you can handle attachments, recipients, and even use DKIM to check that a message is genuine before trusting what it says.

Examples

You can scroll down for a cookbook of common examples, or watch as I build a full disposable-email-address service, and publish it on the web, in four minutes:

Example Snippets

Watch video

Video example: Disposable Email

Note: We skim past the UI building pretty fast in that video. If you want to see how it’s done, check out our other tutorials for a slower explanation.



Sample Email Code

Here are a few things you might want to do with email. You can follow along from these code snippets, or view them all in the Anvil editor:

1. Receiving email and saving it in a database

@anvil.email.handle_message
def incoming_email(msg):
  app_tables.incoming_messages.add_row(
    from_addr=msg.envelope.sender,
    text=msg.text
  )

2. Replying to an email you’ve received

@anvil.email.handle_message
def incoming_email(msg):
  msg.reply(text="Thank you for your message.")

3. Sending email

@anvil.server.callable
def send_a_message(txt):
  anvil.email.send(
    to=["someone@gmail.com"],
    cc=["Someone Else <someone.else@gmail.com>"],
    subject="Hello World",
    text="Hi there!"
  )

4. Handling attachments

All attachments are Anvil Media objects. This means you can upload them from web browsers, store them in databases, make them downloadable, and more.

@anvil.server.callable
def send_by_email(file):
  anvil.email.send(
    to="me@example.com",
    subject="New upload",
    attachments=[file]
  )

Incoming attachments are just as straightforward. Here’s how to save all attachments in a database:

@anvil.email.handle_message
def incoming_email(msg):
  for f in msg.attachments:
    app_tables.files.add_row(file=f)

5. Authenticating senders

Email has historically been easy to spoof. Helpfully, many providers now support DKIM, which lets you verify that the email actually came from the domain it says it did.

The dkim property of the message contains details about all that message’s valid DKIM signatures, and a shortcut to check whether it’s signed by the address in msg.envelope.from_address:

@anvil.email.handle_message
def incoming_email(msg):
  if msg.envelope.from_address == 'me@example.com'
      and msg.dkim.valid_from_sender:
    msg.reply(text="You're the real deal!")

There’s a shorthand, if you only want to accept DKIM-authenticated messages (and reject all others):

@anvil.email.handle_message(require_dkim=True)
def incoming_email(msg):
  if msg.envelope.from_address == 'me@example.com':
    msg.reply(text="You're the real deal!")

6. Rejecting (“bouncing”) messages

@anvil.email.handle_message
def incoming_email(msg):
  raise anvil.email.DeliveryFailure("Nope")


Try it yourself

Start writing email-driven apps for free with Anvil:


You can also read more about the Email service in the Anvil reference docs.