{"id":19143150,"url":"https://github.com/devenes/yag-smtp-client","last_synced_at":"2026-06-17T08:32:13.008Z","repository":{"id":40466587,"uuid":"474339798","full_name":"devenes/yag-smtp-client","owner":"devenes","description":"Simple way to send email via GMAIL/STMP","archived":false,"fork":false,"pushed_at":"2022-05-06T15:44:26.000Z","size":173,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-22T19:25:51.155Z","etag":null,"topics":["email","gmail","pypi","python","smtp","smtp-server","yag","yagmail"],"latest_commit_sha":null,"homepage":"https://devenes.github.io/yag-basic/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devenes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-03-26T12:23:35.000Z","updated_at":"2023-08-30T02:10:41.000Z","dependencies_parsed_at":"2022-08-09T21:20:22.803Z","dependency_job_id":null,"html_url":"https://github.com/devenes/yag-smtp-client","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/devenes/yag-smtp-client","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fyag-smtp-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fyag-smtp-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fyag-smtp-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fyag-smtp-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devenes","download_url":"https://codeload.github.com/devenes/yag-smtp-client/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devenes%2Fyag-smtp-client/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34441284,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-17T02:00:05.408Z","response_time":127,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["email","gmail","pypi","python","smtp","smtp-server","yag","yagmail"],"created_at":"2024-11-09T07:29:43.259Z","updated_at":"2026-06-17T08:32:12.989Z","avatar_url":"https://github.com/devenes.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# yagmail -- Yet Another GMAIL/SMTP client\n\n[![Join the chat at https://gitter.im/kootenpv/yagmail](https://badges.gitter.im/kootenpv/yagmail.svg)](https://gitter.im/kootenpv/yagmail?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![PyPI](https://img.shields.io/pypi/v/yagmail.svg?style=flat-square)](https://pypi.python.org/pypi/yagmail/)\n[![PyPI](https://img.shields.io/pypi/pyversions/yagmail.svg?style=flat-square)](https://pypi.python.org/pypi/yagmail/)\n\n![yag](yag.png)\n\nThe goal here is to make it as simple and painless as possible to send emails.\n\nIn the end, your code will look something like this:\n\n```python\nimport yagmail\nyag = yagmail.SMTP()\ncontents = ['This is the body, and here is just text http://somedomain/image.png',\n            'You can find an audio file attached.', '/local/path/song.mp3']\nyag.send('to@someone.com', 'subject', contents)\n```\n\nOr a simple one-liner:\n\n```python\nyagmail.SMTP('mygmailusername').send('to@someone.com', 'subject', 'This is the body')\n```\n\nNote that it will read the password securely from your keyring (read below). If you don't want this, you can also initialize with:\n\n```python\nyag = yagmail.SMTP('mygmailusername', 'mygmailpassword')\n```\n\n## Send Email using API\n\n| Parameter  | Type     | Description                   |\n| :--------- | :------- | :---------------------------- |\n| `receiver` | `string` | Email address of the receiver |\n| `subject`  | `string` | Subject of the email          |\n| `contents` | `string` | Contents of the email         |\n\n![yagmail-api](./readme-content/postman.jpg)\n\n## Automate sending Email using API\n\n![yagmail-smtp](./readme-content/mail.jpg)\n\n## Autherization Gmail Accounts with SMTP\n\nYou can use your gmail account credentials to send emails in Python application with yagmail.\n\nIf you are using gmail, you can use the following settings to add your gmail account to your keyring: [Enable less secure apps](https://myaccount.google.com/lesssecureapps)\n\n\u003e You need to enable access to less secure apps in your gmail account settings.\n\n\u003cimg src=\"./readme-content/gmail.png\"/\u003e\n\n---\n\n### Table of Contents\n\n| Section                                             | Explanation                                                   |\n| --------------------------------------------------- | ------------------------------------------------------------- |\n| [Install](#install)                                 | Find the instructions on how to install yagmail here          |\n| [Username and password](#username-and-password)     | No more need to fill in username and password in scripts      |\n| [Start a connection](#start-a-connection)           | Get started                                                   |\n| [Usability](#usability)                             | Shows some usage patterns for sending                         |\n| [Recipients](#recipients)                           | How to send to multiple people, give an alias or send to self |\n| [Magical contents](#magical-contents)               | Really easy to send text, html, images and attachments        |\n| [Attaching files](#attaching-files)                 | How attach files to the email                                 |\n| [DKIM Support](#dkim-support)                       | Add DKIM signature to your emails with your private key       |\n| [Feedback](#feedback)                               | How to send me feedback                                       |\n| [Roadmap (and priorities)](#roadmap-and-priorities) | Yup                                                           |\n| [Errors](#errors)                                   | List of common errors for people dealing with sending emails  |\n\n### Install\n\nFor Python 2.x and Python 3.x respectively:\n\n```python\npip install yagmail[all]\npip3 install yagmail[all]\n\n```\n\nIf you get problems installing keyring, try installing without, i.e. `pip install yagmail`.\n\nAs a side note, `yagmail` can now also be used to send emails from the command line.\n\n### Username and password\n\n[keyring quoted](https://pypi.python.org/pypi/keyring#what-is-python-keyring-lib):\n\n\u003e The Python `keyring` lib provides a easy way to access the system keyring service from python. It can be used in any application that needs safe password storage.\n\nYou know you want it. Set it up by opening a Python interpreter and running:\n\n```python\nimport yagmail\nyagmail.register('mygmailusername', 'mygmailpassword')\n```\n\nIn fact, it is just a wrapper for `keyring.set_password('yagmail', 'mygmailusername', 'mygmailpassword')`.\n\nWhen no password is given and the user is not found in the keyring, `getpass.getpass()` is used to prompt the user for a password. Upon entering this once, it can be stored in the keyring and never asked again.\n\nAnother convenience can be to save a .yagmail file in your home folder, containing just the email username. You can then omit everything, and simply use `yagmail.SMTP()` to connect. Of course, this wouldn't work with more accounts, but it might be a nice default. Upon request I'll consider adding more details to this .yagmail file (host, port and other settings).\n\n### Start a connection\n\n```python\nyag = yagmail.SMTP('mygmailusername')\n```\n\nNote that this connection is reusable, closable and when it leaves scope it will **clean up after itself in CPython**.\n\nAs [tilgovi](https://github.com/tilgovi) points out in [#39](https://github.com/kootenpv/yagmail/issues/39), SMTP does not automatically close in **PyPy**. The context manager `with` should be used in that case.\n\n### Usability\n\nDefining some variables:\n\n```python\nto = 'santa@someone.com'\nto2 = 'easterbunny@someone.com'\nto3 = 'sky@pip-package.com'\nsubject = 'This is obviously the subject'\nbody = 'This is obviously the body'\nhtml = '\u003ca href=\"https://pypi.python.org/pypi/sky/\"\u003eClick me!\u003c/a\u003e'\nimg = '/local/file/bunny.png'\n```\n\nAll variables are optional, and know that not even `to` is required (you'll send an email to yourself):\n\n```python\nyag.send(to = to, subject = subject, contents = body)\nyag.send(to = to, subject = subject, contents = [body, html, img])\nyag.send(contents = [body, img])\n```\n\nFurthermore, if you do not want to be explicit, you can do the following:\n\n```python\nyag.send(to, subject, [body, img])\n```\n\n### Recipients\n\nIt is also possible to send to a group of people by providing a list of email strings rather than a single string:\n\n```python\nyag.send(to = to)\nyag.send(to = [to, to2]) # List or tuples for emailadresses *without* aliases\nyag.send(to = {to : 'Alias1'}) # Dictionary for emailaddress *with* aliases\nyag.send(to = {to : 'Alias1', to2 : 'Alias2'}\n```\n\nGiving no `to` argument will send an email to yourself. In that sense, `yagmail.SMTP().send()` can already send an email.\nBe aware that if no explicit `to = ...` is used, the first argument will be used to send to. Can be avoided like:\n\n```python\nyag.send(subject = 'to self', contents = 'hi!')\n```\n\nNote that by default all email addresses are conservatively validated using `soft_email_validation==True` (default).\n\n### Oauth2\n\nIt is even safer to use Oauth2 for authentication, as you can revoke the rights of tokens.\n\n[This](http://blog.macuyiko.com/post/2016/how-to-send-html-mails-with-oauth2-and-gmail-in-python.html) is one of the best sources, upon which the oauth2 code is heavily based.\n\nThe code:\n\n```python\nyag = yagmail.SMTP(\"user@gmail.com\", oauth2_file=\"~/oauth2_creds.json\")\nyag.send(subject=\"Great!\")\n```\n\nIt will prompt for a `google_client_id` and a `google_client_secret`, when the file cannot be found. These variables can be obtained following [the previous link](http://blog.macuyiko.com/post/2016/how-to-send-html-mails-with-oauth2-and-gmail-in-python.html).\n\nAfter you provide them, a link will be shown in the terminal that you should followed to obtain a `google_refresh_token`. Paste this again, and you're set up!\n\nNote that people who obtain the file can send emails, but nothing else. As soon as you notice, you can simply disable the token.\n\n### Magical `contents`\n\nThe `contents` argument will be smartly guessed. It can be passed a string (which will be turned into a list); or a list. For each object in the list:\n\n- If it is a dictionary it will assume the key is the content, and the value is an alias (only for images currently!)\n  e.g. {'/path/to/image.png' : 'MyPicture'}\n- It will try to see if the content (string) can be read as a file locally,\n  e.g. '/path/to/image.png'\n- if impossible, it will check if the string is valid html\n  e.g. `\u003ch1\u003eThis is a big title\u003c/h1\u003e`\n- if not, it must be text.\n  e.g. 'Hi Dorika!'\n\nNote that local files can be html (inline); everything else will be attached.\n\nLocal files require to have an extension for their content type to be inferred.\n\nAs of version 0.4.94, `raw` and `inline` have been added.\n\n- `raw` ensures a string will not receive any \"magic\" (inlining, html, attaching)\n- `inline` will make an image appear in the text.\n\n### Attaching Files\n\nThere are multiple ways to attach files in the `attachments` parameter (in addition to magical `contents` parameter).\n\n1. One can pass a list of paths i.e.\n\n```python\nyag.send(to=recipients,\n         subject=email_subject,\n         contents=contents,\n         attachments=['path/to/attachment1.png', 'path/to/attachment2.pdf', 'path/to/attachment3.zip']\n)\n```\n\n2. One can pass an instance of [`io.IOBase`](https://docs.python.org/3/library/io.html#io.IOBase).\n\n```python\nwith open('path/to/attachment', 'rb') as f:\n    yag.send(to=recipients,\n             subject=email_subject,\n             contents=contents,\n             attachments=f\n             )\n```\n\nIn this example `f` is an instance of `_io.BufferedReader` a subclass of the abstract class `io.IOBase`.\n\n`f` has in this example the attribute `.name`, which is used by yagmail as filename as well as to detect the correct MIME-type.\nNot all `io.IOBase` instances have the `.name` attribute in which case yagmail names the attachments `attachment1`, `attachment2`, ... without a file extension!\nTherefore, it is highly recommended setting the filename with extension manually e.g. `f.name = 'my_document.pdf'`\n\nA real-world example would be if the attachment is retrieved from a different source than the disk (e.g. downloaded from the internet or [uploaded by a user in a web-application](https://docs.streamlit.io/en/stable/api.html#streamlit.file_uploader))\n\n### DKIM Support\n\nTo send emails with dkim signature, you need to install the package with all related packages.\n\n```\npip install yagmail[all]\n# or\npip install yagmail[dkim]\n```\n\nUsage:\n\n```python\nfrom yagmail import SMTP\nfrom yagmail.dkim import DKIM\nfrom pathlib import Path\n\n# load private key from file/secrets manager\nprivate_key = Path(\"privkey.pem\").read_bytes()\n\ndkim_obj = DKIM(\n  domain=b\"a.com\",\n  selector=b\"selector\",\n  private_key=private_key,\n  include_headers=[b\"To\", b\"From\", b\"Subject\"],\n  # To include all default headers just pass None instead\n  # include_headers=None,\n)\n\nyag = SMTP(dkim=dkim_obj)\n\n# all the rest is the same\n```\n\n### Feedback\n\nI'll try to respond to issues within 24 hours at Github.....\n\nAnd please send me a line of feedback with `SMTP().feedback('Great job!')` :-)\n\n### Roadmap (and priorities)\n\n- ~~Added possibility of Image~~\n- ~~Optional SMTP arguments should go with \\*\\*kwargs to my SMTP~~\n- ~~CC/BCC (high)~~\n- ~~Custom names (high)~~\n- ~~Allow send to return a preview rather than to actually send~~\n- ~~Just use attachments in \"contents\", being smart guessed (high, complex)~~\n- ~~Attachments (contents) in a list so they actually define the order (medium)~~\n- ~~Use lxml to see if it can parse the html (low)~~\n- ~~Added tests (high)~~\n- ~~Allow caching of content (low)~~\n- ~~Extra other types (low)~~ (for example, mp3 also works, let me know if something does not work)\n- ~~Probably a naming issue with content type/default type~~\n- ~~Choose inline or not somehow (high)~~\n- ~~Make lxml module optional magic (high)~~\n- ~~Provide automatic fallback for complex content(medium)~~ (should work)\n- ~~`yagmail` as a command on CLI upon install~~\n- ~~Added `feedback` function on SMTP to be able to send me feedback directly :-)~~\n- ~~Added the option to validate emailaddresses...~~\n- ~~however, I'm unhappy with the error handling/logging of wrong emails~~\n- ~~Logging count \u0026 mail capability (very low)~~\n- ~~Add documentation to exception classes (low)~~\n- ~~add `raw` and `inline`~~\n- ~~oauth2~~\n- ~~Travis CI integration ~~\n- ~~ Add documentation to all functions (high, halfway) ~~\n- Prepare for official 1.0\n- Go over documentation again (medium)\n- Allow `.yagmail` file to contain more parameters (medium)\n- Add option to shrink images (low)\n\n### Errors\n\n- Make sure you have a keyring entry (see section \u003ca href=\"#no-more-password-and-username\"\u003eNo more password and username\u003c/a\u003e), or use getpass to register. I discourage to use username / password in scripts.\n\n- [`smtplib.SMTPException: SMTP AUTH extension not supported by server`](http://stackoverflow.com/questions/10147455/trying-to-send-email-gmail-as-mail-provider-using-python)\n\n- [`SMTPAuthenticationError: Application-specific password required`](https://support.google.com/accounts/answer/185833)\n\n- **YagAddressError**: This means that the address was given in an invalid format. Note that `From` can either be a string, or a dictionary where the key is an `email`, and the value is an `alias` {'sample@gmail.com': 'Sam'}. In the case of 'to', it can either be a string (`email`), a list of emails (email addresses without aliases) or a dictionary where keys are the email addresses and the values indicate the aliases.\n\n- **YagInvalidEmailAddress**: Note that this will only filter out syntax mistakes in emailaddresses. If a human would think it is probably a valid email, it will most likely pass. However, it could still very well be that the actual emailaddress has simply not be claimed by anyone (so then this function fails to devalidate).\n\n- Click to enable the email for being used externally https://www.google.com/settings/security/lesssecureapps\n\n- Make sure you have a working internet connection\n\n- If you get an `ImportError` try to install with `sudo`, see issue #13\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevenes%2Fyag-smtp-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevenes%2Fyag-smtp-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevenes%2Fyag-smtp-client/lists"}