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 :class:`yagmail.Client`. The two primary methods are: 1. **With App Password**: Pass your username and Google App Password: .. code-block:: python 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: .. code-block:: python 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 :ref:`configuring_credentials`. Closing and reusing the Connection ---------------------------------- By default, :class:`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 :class:`yagmail.Client` with ``with`` instead: .. code-block:: python 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: .. code-block:: python yag = yagmail.Client('mygmailusername', 'mygmailpassword') yag.send(to="you@gmail.com", contents="Hello!") Alternatively, you can manually close and re-use the connection with :meth:`yagmail.Client.close` and :meth:`yagmail.Client.login`. Sending E-Mails --------------- :meth:`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: .. code-block:: python 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``: .. code-block:: python 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: .. code-block:: python recipients = { 'aliased@mike.com': 'Mike', 'aliased@fred.com': 'Fred' } yag.send(to=recipients, contents="Hello, Mike and Fred!") Magical ``contents`` -------------------- The ``contents`` argument of :meth:`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: .. code-block:: python 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 ``

This is a big title!

``. - 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 :class:`yagmail.raw`, a subclass of :class:`str`. If you intend to **inline an image instead of attaching it**, you can use :class:`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: .. code-block:: python 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'] ) 2. **Pass an IO Stream**: You can pass an instance of :class:`io.IOBase` (such as a file object): .. code-block:: python 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: .. code-block:: bash pip install yagmail[dkim] Then, configure and pass a :class:`yagmail.dkim.DKIM` configuration object to your client instance: .. code-block:: python 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 :class:`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: .. code-block:: python 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()``: .. code-block:: python 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: .. code-block:: python # 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``: .. code-block:: python 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``.