Open-source project
kootenpv/yagmail avatar
kootenpv/yagmail

yagmail hides the SMTP boilerplate and moves the hard part to Google credentials

Send email in Python conveniently for gmail using yagmail

2,736 stars266 forksPythonMIT

At a glance

What is it?
A Python client for Gmail with one required dependency and two extras. Its edge cases are the PyPy connection that never closes, the seven day OAuth token, and a send call whose first positional argument silently becomes the recipient.
Who is it for?
Use yagmail when the mail comes from a Gmail account you control and the application-specific password or the Desktop-type OAuth client is already in hand. Do not use it to send from anything but Gmail, since the credential model and the mail.google.com scope are written for one provider.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 132 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A Client object and one send call replace the SMTP boilerplate

yagmail is one class wrapped around one Gmail SMTP session, and the whole introduction fits in five lines. Build a Client, build a contents list, call send. The preferred class is `yagmail.Client`; the older name `yagmail.SMTP` survives as a backward-compatible alias, so either name reaches the same object. The connection is reusable, so a single Client can carry a batch of messages rather than logging in per message, and it is closable. What the design really saves is the contents argument: a plain string, an HTML string and a filesystem path all go into one list, and the README passes a URL inside a body sentence, a sentence announcing an audio attachment and a local song path in a single call. Installation is one line too.

bash
pip install yagmail[all]

Note that the extras bracket is not decoration. A plain `pip install yagmail` gives you a smaller package than the line the README tells you to run, and the difference is spelled out further down in the metadata.

CPython closes the socket when the Client goes out of scope, PyPy does not

The README states that this connection is reusable, closable, and cleans up after itself in CPython when it leaves scope. It then names tilgovi in issue #39 for the other runtime: SMTP and Client connections do not automatically close in PyPy. The fix it gives is the `with` context manager. That makes this the one behaviour in the library that depends on the interpreter rather than on a version number, and it is a silent difference: on PyPy the socket stays open until the process exits, so a loop that creates one Client per message accumulates open connections instead of failing. The usage examples never show a `with` block, so the visible instructions leave the PyPy case to the reader to apply from that single sentence. On CPython the same code needs no such care, which is why the difference stays invisible until a project changes interpreter.

Gmail rejects account passwords over SMTP, so the credential is one of two things

Authentication is the first place the README diverges from the classic recipe. For Gmail it says to use an Application-Specific Password as the password, because regular account passwords no longer work over SMTP. For revocable, scope-limited credentials it points at OAuth2 instead, and the whole setup is two lines:

python
yag = yagmail.Client("[email protected]", oauth2_file="~/oauth2_creds.json")
yag.send(subject="Great!")

When that file is not found, the library prompts for a `google_client_id` and a `google_client_secret`. After you supply them a link is printed in the terminal, you follow it to obtain a `google_refresh_token`, and you paste that back. The token is written to the path you passed. The scope behind it is the restricted `https://mail.google.com/` one, and the README credits a 2016 blog post as the source the OAuth2 code is heavily based on, which is worth knowing before you go looking for a newer flow.

The consent screen decides whether the token lives 7 days or keeps working

A yagmail OAuth authorization expires after 7 days unless one setting is changed on Google's side. The Cloud project's OAuth consent screen must be in In production publishing status, checked at the credentials console, and the OAuth client ID must be of type Desktop. For personal use the README says that is all you need: hit Publish App, and an unverified-app warning appears during the OAuth flow that you can click through, after which the 7-day expiry no longer applies. Formal Google verification, and the annual CASA security assessment that the restricted `https://mail.google.com/` scope requires, is only needed to remove that warning for external users. The same section states plainly that people who obtain the credentials file can send emails but nothing else, and that disabling the token is the remedy once you notice. It says nothing about restricting the file, and the example path puts it in your home directory.

Omit the to argument and the first positional argument becomes the recipient

Every argument is optional, including the recipient. Calling send with no `to` sends the mail to yourself, which means `yagmail.Client().send()` already sends an email, and the README warns about the same thing from the other direction: if no explicit `to = ...` is used, the first argument is used to send to. So a call written as `yag.send('to self', contents='hi!')` puts a subject where a recipient belongs. The README's own escape hatch is to name every argument. Recipients come in three shapes, and the shape decides whether you get aliases:

python
yag.send(to = [to, to2]) # List or tuples for emailadresses *without* aliases
yag.send(to = {to : 'Alias1'}) # Dictionary for emailaddress *with* aliases

Separately, all addresses are conservatively validated by default, with `soft_email_validation==True`.

One hard dependency and two extras decide what actually installs

The project metadata carries a single unconditional dependency, premailer. Optional extras sit beside it: `all` pulls in keyring and dkimpy, and a narrower `dkim` extra pulls in dkimpy alone. The install line the README gives, `pip install yagmail[all]`, therefore adds two packages beyond the base one, and keyring, which is where a client typically looks for stored credentials, is one of them. If you follow the plain package name instead you get neither, and the visible instructions never say what breaks. The table of contents also promises a DKIM Support chapter described as adding a signature with your private key, and a dkim extra exists to serve it, but the chapter itself is not part of the instructions that follow the OAuth2 section. The extra and the feature are documented out of step with each other.

Python 3.8 is the floor and the classifiers stop at 3.13

`requires-python` is set to `>=3.8`, and the classifiers name six interpreters, 3.8 through 3.13, one per line. A 3.14 interpreter is therefore inside the declared floor and outside the declared test matrix at the same time, with nothing in the metadata telling you which situation you are in. The build side is a modern one: `setuptools>=61.0.0` as the requirement, `setuptools.build_meta` as the backend, and no `setup.py` or `setup.cfg` at the top level. The version is declared dynamic, so it is read from the package rather than written in the metadata. Two other top level details are worth a look before you file anything. The repository carries both README.md and README.rst while the metadata points at README.md, and the keyword list tags the project under Debuggers, which is a strange classification for a mail client and probably a leftover from another project.

The visible instructions stop one word into the Magical contents chapter

The table of contents names eleven chapters: Install, Start a connection, Usability, Recipients, Magical contents, Attaching files, Asynchronous Client, DKIM Support, Feedback, Roadmap (and priorities), and Errors, where that last one is described as a list of common errors. The instructions that follow cover Install, Start a connection, Usability, Recipients and Oauth2, including the section on preventing authorization from expiring, and then reach a heading that reads `### Mag`. That is where they stop, one word into the chapter the contents page calls Magical contents, so what lives in Attaching files, the asyncio client, the DKIM chapter, the roadmap and the list of common errors is not written down here. The introduction does make a claim about one of them, saying an asynchronous `asyncio` version is built in and pointing at the Asynchronous Client chapter. Treat that as a promise, not a description. The project metadata ends the same way, inside its Homepage value, one character short of the repository name.

Editorial conclusion

Use yagmail when the mail comes from a Gmail account you control and the application-specific password or the Desktop-type OAuth client is already in hand. Do not use it to send from anything but Gmail, since the credential model and the mail.google.com scope are written for one provider. Before you trust it in a service, read the section on PyPy and wrap the Client in a context manager, decide where the token file lives and who can read it, and check whether your Cloud project consent screen is in production, because that single setting decides whether the authorization lasts a week or keeps working.

Frequently asked questions

How do I install yagmail?

The README gives one line, `pip install yagmail[all]`. The extras bracket is optional: a plain `pip install yagmail` installs only premailer, while the `all` extra adds keyring and dkimpy.

How do I use yagmail to send an email?

Create `yagmail.Client` with a username and an Application-Specific Password, then call send with a contents list. The connection is reusable and closable, and it closes on its own in CPython but not in PyPy, where the README says to use the `with` context manager.

Is yagmail safe to use for a service?

The credentials are the risk, and the README is explicit about them. An OAuth credentials file lets its holder send mail and nothing else, and disabling the token is the stated remedy. That authorization expires after 7 days unless the Cloud project's consent screen is in In production status with a Desktop type client ID, and the credentials file path in the example sits in your home directory with no file mode guidance given.

Official sources

  1. Issues
  2. kootenpv/yagmail on GitHub
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/kootenpv-yagmail.svg)](https://hysenlabs.com/projects/kootenpv-yagmail)