Usage

This document aims to show how to use yagmail in your programs. Most of what is shown here is also available to see in the README, some content may be duplicated for completeness.

Start a Connection

To initialize a connection, you instantiate yagmail.Client. The two primary methods are:

  1. With App Password: Pass your username and Google App Password:

    yag = yagmail.Client('mygmailusername', 'myapppassword')
    

    Note

    For GMail, you must use an Application-Specific Password as the password (your regular Google account password will no longer work over SMTP).

  2. With OAuth2: Pass your email and the path to an OAuth2 credentials file:

    yag = yagmail.Client('user@gmail.com', oauth2_file='~/oauth2_creds.json')
    

For other authentication options (like utilizing the system keyring or configuration files) and detailed setup instructions, refer to Configuring Credentials.

Closing and reusing the Connection

By default, yagmail.Client will clean up after itself in CPython. This is an implementation detail of CPython and as such may not work in other implementations such as PyPy (reported in issue #39). In those cases, you can use yagmail.Client with with instead:

with yagmail.Client('mygmailusername', 'mygmailpassword') as yag:
    yag.send(to='you@gmail.com', contents="Hello!")

Or, using the standard constructor directly without a context manager:

yag = yagmail.Client('mygmailusername', 'mygmailpassword')
yag.send(to="you@gmail.com", contents="Hello!")

Alternatively, you can manually close and re-use the connection with yagmail.Client.close() and yagmail.Client.login().

Sending E-Mails

yagmail.Client.send() is a fairly versatile method that allows you to adjust more or less anything about your Mail. First of all, all parameters are optional. If you omit the recipient (specified with to), you will send an E-Mail to yourself.

Since the use of the (keyword) arguments are fairly obvious, they will simply be listed here:

  • to

  • subject

  • contents

  • attachments

  • cc

  • bcc

  • preview_only

  • headers

Some of these - namely to and contents - have some magic associated with them which will be outlined in the following sections.

E-Mail recipients

You can send an E-Mail to a single user by simply passing a string with either a GMail username (@gmail.com will be appended automatically), or with a full E-Mail address:

yag.send(to='mike@gmail.com', contents="Hello, Mike!")

Alternatively, you can send E-Mails to a group of people by either passing a list or a tuple of E-Mail addresses as to:

yag.send(to=['to@someone.com', 'for@someone.com'], contents="Hello there!")

These E-Mail addresses were passed without any aliases. If you wish to use aliases for the E-Mail addresses, provide a dictionary mapped in the form {address: alias}, for example:

recipients = {
    'aliased@mike.com': 'Mike',
    'aliased@fred.com': 'Fred'
}
yag.send(to=recipients, contents="Hello, Mike and Fred!")

Magical contents

The contents argument of yagmail.Client.send() will be smartly guessed. You can pass it a string with your contents or a list of elements which are either:

  • If it is a dictionary, then it will be assumed that the key is the content and the value is an alias (currently, this only applies to images). For example:

contents = [
    "Hello Mike! Here is a picture I took last week:",
    {'path/to/my/image.png': 'PictureForMike'}
]
  • If it is a string, then it will first check whether the content of the string can be read as a file locally, for example 'path/to/my/image.png'. These files require an extension for their content type to be inferred.

  • If it could not be read locally, then it checks whether the string is valid HTML, such as <h1>This is a big title!</h1>.

  • If it was not valid HTML either, then it must be text, such as "Hello, Mike!".

If you want to ensure that a string is treated as text and should not be checked for any other content as described above, you can use yagmail.raw, a subclass of str.

If you intend to inline an image instead of attaching it, you can use yagmail.inline.

Attaching Files

There are multiple ways to attach files using the attachments parameter (in addition to the magical contents parameter):

  1. Pass a List of Paths: You can pass a list of local file paths as a list of strings:

yag.send(
    to='to@someone.com',
    subject='File Attachments',
    contents='Here are the files you requested.',
    attachments=['path/to/attachment1.png', 'path/to/attachment2.pdf']
)
  1. Pass an IO Stream: You can pass an instance of io.IOBase (such as a file object):

with open('path/to/attachment.pdf', 'rb') as f:
    yag.send(
        to='to@someone.com',
        subject='File Attachments',
        contents='Attached is the PDF.',
        attachments=f
    )

Note

When passing an IO stream, yagmail will look for the .name attribute to determine the filename and detect the MIME-type. If your IO stream does not have a .name attribute, it is highly recommended to set it manually (e.g., f.name = 'document.pdf') to avoid attachments being named generic names like attachment1 without an extension.

DKIM Support

To send emails signed with a DKIM signature, you will first need to install the package with all optional dkim dependencies:

pip install yagmail[dkim]

Then, configure and pass a yagmail.dkim.DKIM configuration object to your client instance:

from yagmail import Client
from yagmail.dkim import DKIM
from pathlib import Path

# Load private key bytes
private_key = Path("privkey.pem").read_bytes()

dkim_obj = DKIM(
    domain=b"example.com",
    selector=b"selector",
    private_key=private_key,
    include_headers=[b"To", b"From", b"Subject"] # Or pass None for defaults
)

yag = Client(dkim=dkim_obj)
yag.send(to="to@someone.com", subject="DKIM Signed Email", contents="Hi!")

Connection Stability (Auto-reconnect)

The synchronous Client features automatic reconnection. If the SMTP server drops the connection (raising SMTPServerDisconnected) during a send operation, yagmail will automatically catch the exception, log back in, and retry sending the email up to 3 times before raising the error.

Asynchronous Client

If you are building an asynchronous application (e.g. using asyncio, FastAPI, Sanic, or Tornado), yagmail provides a native, dependency-free asynchronous client called yagmail.AsyncClient (also aliased as yagmail.AsyncSMTP and yagmail.AIOSMTP).

Starting and Closing Connections

The recommended way to use the asynchronous client is as an asynchronous context manager:

import asyncio
import yagmail

async def main():
    async with yagmail.AsyncClient('user@gmail.com', 'app-password') as yag:
        await yag.send(to='to@someone.com', subject='Async Email', contents='Hello!')

asyncio.run(main())

Alternatively, you can manually manage the connection using login() and aclose():

async def main():
    yag = yagmail.AsyncClient('user@gmail.com', 'app-password')
    await yag.login()
    await yag.send(to='to@someone.com', subject='Manual Async', contents='Hello!')
    await yag.aclose()

asyncio.run(main())

Sending Emails & Attachments

The send() method on AsyncClient accepts the same parameters (and performs the same “magical” guessing of content types and attachments) as the synchronous Client, but must be awaited:

# Sending to multiple recipients with attachments asynchronously
await yag.send(
    to=['one@gmail.com', 'two@gmail.com'],
    subject='Async Attachments',
    contents=['Hello!', '/path/to/local/file.png'],
    attachments=['/path/to/another/file.pdf']
)

DKIM Support in Async

You can pass the same DKIM configuration object when instantiating AsyncClient:

from yagmail import AsyncClient
from yagmail.dkim import DKIM
from pathlib import Path

private_key = Path("privkey.pem").read_bytes()

dkim_obj = DKIM(
    domain=b"example.com",
    selector=b"selector",
    private_key=private_key
)

async with AsyncClient(dkim=dkim_obj) as yag:
    await yag.send(subject="DKIM Signed Async Email", contents="Hi!")

Auto-reconnect & Concurrency Safety

  • Auto-reconnect: Just like the synchronous client, AsyncClient automatically handles reconnection. If the connection drops mid-send, it will automatically log back in and retry sending up to 3 times.

  • Concurrency-safe Locks: You can share a single AsyncClient instance across concurrent async tasks safely. The client implements internal asynchronous locks (send_lock and login_lock) to serialize access to the underlying socket connection, preventing race conditions or interleaved data blocks on the shared connection.

Using yagmail from the command line

yagmail includes a command-line application, simply called with yagmail after you installed it. To view a full reference on how to use this, run yagmail --help.