{"id":19414287,"url":"https://github.com/nickythelion/manokit","last_synced_at":"2025-06-12T06:33:47.132Z","repository":{"id":57439496,"uuid":"351895354","full_name":"nickythelion/manokit","owner":"nickythelion","description":"A native Python email sender that is so simple that even junior can use it","archived":false,"fork":false,"pushed_at":"2023-09-16T12:11:47.000Z","size":107,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-09-19T14:13:49.363Z","etag":null,"topics":["email","email-sender","manokit","py-libraries","python","python-3","python-library","python3","sender"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nickythelion.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-03-26T19:48:33.000Z","updated_at":"2023-09-12T12:32:11.000Z","dependencies_parsed_at":"2023-09-13T18:36:52.165Z","dependency_job_id":"6372f744-8390-4af7-bed3-7686d9fc626f","html_url":"https://github.com/nickythelion/manokit","commit_stats":null,"previous_names":["nickythelion/manokit"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickythelion%2Fmanokit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickythelion%2Fmanokit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickythelion%2Fmanokit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nickythelion%2Fmanokit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nickythelion","download_url":"https://codeload.github.com/nickythelion/manokit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223953849,"owners_count":17231149,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","email-sender","manokit","py-libraries","python","python-3","python-library","python3","sender"],"created_at":"2024-11-10T12:37:09.615Z","updated_at":"2024-11-10T12:37:10.043Z","avatar_url":"https://github.com/nickythelion.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Manokit\n\n## Table of contents\n- [General Information](#general-information)\n- [Installation](#installation)\n- [v1 vs. v2](#v1-vs-v2)\n- [Structure](#structure)\n    - [Email class](#email-class)\n        - [Initialization](#initialization)\n        - [Authentication](#authentication)\n        - [Adding recipients](#adding-recipients)\n        - [Composing an email](#composing-an-email)\n        - [Custom Email Validation](#custom-email-validation)\n        - [Adding attachments](#adding-attachments)\n        - [Attachment size limit](#attachment-size-limit)\n        - [Sending an email](#sending-an-email)\n        - [Method chaining](#method-chaining)\n    - [Exceptions](#exceptions)\n        - [NotAValidEmailAddressError](#notavalidemailaddresserror)\n        - [EmailError](#emailerror)\n        - [AttachmentError](#attachmenterror)\n- [Changelog](#changelog)\n\n## General information\nManokit is a simple, fully native library for sending emails. It provides an easy-to-use API for creating and sending emails, as well as offers a very customizable structure.\n\nManokit provides 2 modules: the base module name `manokit`, where the `Email` base class is defined, and a module called `manokit.exceptions` where custom exceptions, used by manokit, are defined.\n\n## Installation\nManokit can be installed from the [PyPI](https://pypi.org/project/manokit) using the following command:\n```\npip install manokit\n```\nYou can also download the package from the [releases](https://github.com/nickythelion/manokit/releases) section, or assemble it from source.\n\n## V1 vs. V2\nManokit has reached a point of version separation. Manokit v2's API has been overhauled to provide a more consistent and predictable experience.\n\nThese changes include:\n- All functionality has been moved to a single class, instead of being scattered across 3 classes.\n- Explicit type checking was removed\n- Complete overhaul of properties and their behaviours\n\nSee additional info in our [Changelog](https://github.com/nickythelion/manokit/blob/master/CHANGELOG.md).\n\nAll these changes and updates are aimed at bringing a more pleasant experience to the end user, but they break compatibility. If you are currently using manokit and want to upgrade, make sure to update your codebase accordingly.\n\n## Structure\n\nThis section describes the parts of Manokit, and how to use them.\n\n### Email class\nThe `Email` class is where all the functionality resides.\n\n#### Initialization\nTo begin working with Manokit, simply import the `Email` class and create an instance.\n```python\nfrom manokit import Email\n\nemail = Email(smtp_host=\"smtp.gmail.com\", smtp_port=587)\n```\nDuring initialization you can also adjust the attachment size limit (see [attachment size limit](#attachment-size-limit) for details), by specifying the new limit in bytes, like this:\n```python\nfrom manokit import Email\n\nsmall_email = Email(\"smtp.gmail.com\", 587, filesize_limit=100)\n```\nIn the example above we have reduced the attachment size limit from 25 MB to 100 bytes. \n\n#### Authentication\nIn order to send an email, the client must first authenticate themselves with their SMTP server. Using Manokit, the authentication process looks like this:\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\n```\n\u003e This example passes the credentials as plain text for the sake of illustration.\n\u003e **Please use environment variables/other secure ways of storing credentials when logging in!**\n\nAs of May 30, 2022, Google introduced [some changes to their API](https://support.google.com/accounts/answer/6010255) that now require users to have an App Password. Manokit supports logging in with your App Password. Just pass your App Password instead of your regular password, like this:\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"ccfv jels tttm hshe\")\n```\nBy default, Manokit uses STARTTLS to encrypt the communication and make it more secure. If you would like to use SSL instead, simply disable STARTTLS during authentication and updating the port.\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 465)\nemail.login(\n    username=\"manokit@gmail.com\", \n    password=\"manokit_is_cool\", \n    use_starttls=False,\n)\n```\nManokit does not support unencrypted communication over SMTP port 25.\n\nAfter you have finished with Manokit, you need to call `logout()` function to close the SMTP session.\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 465)\nemail.login(\n    username=\"manokit@gmail.com\", \n    password=\"manokit_is_cool\", \n    use_starttls=False,\n)\n\n# Your email stuff\n\nemail.logout()\n```\n\n#### Adding recipients\nTo add an email address to the list of recipients, simply call the appropriate function:\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"buddy@examplecorp.com\")\n\nemail.logout()\n```\nFor now, you can add recipients one at a time, so for each one you need to call the `add_recipient` function separately.\n\nIf you want to CC a person instead, replace the `add_recipient` function with `add_cc`:\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"boss@examplecorp.com\") # This is important\nemail.add_cc(\"buddy@examplecorp.com\")\n\nemail.logout()\n```\nHowever, make sure to add at least one recipient, or else the email will not be sent.\n\nSame thing for BCC:\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"boss@examplecorp.com\")\nemail.add_bcc(\"spy@rivalcorp.com\")\n\nemail.logout()\n```\nIt is important to know that if you try to add an email address to either recipients, CC, or BCC when it already is added to one of them, **these function will have no effect**.\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"buddy@examplecorp.com\")\nemail.add_cc(\"buddy@examplecorp.com\")\n\nprint(len(email.rec)) # Output: 1\nprint(len(email.cc)) # Output: 0\n\nemail.logout()\n```\n#### Composing an email\nA simple email consists of a subject and a body. Both of these things are set by Manokit's `set_subject` and `set_body` functions, respectively.\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"buddy@examplecorp.com\")\n\nemail.set_subject(\"Manokit is kinda cool!\")\nemail.set_body(\"Hey, you heard about that library called Manokit? I tried it and it is nice ngl. Give it a try!\")\n\nemail.logout()\n\n```\nThe use of these functions is not compulsory, however. Manokit defaults the subject and the body to `\u003cno subject\u003e` and `\u003cno body\u003e`, respectively.\n\nManokit encodes the body of an email as `text/html`, rather than `text/plain`. This allows you to use HTML markup for styling and emphasis.\n\n#### Custom Email Validation\nBy default, Manokit will validate user emails in certain cases (e.g. adding recipients, logging in, adding addresses to CC and BCC, etc) using a general-purpose regular expression.\n\nSpecifically, the regular expression used is this one: ```^[-_+.\\d\\w]+@[-_+\\d\\w]+(?:\\.{1}[\\w]+)+$```\n\nHowever, if you find this validation mechanism unsuitable for their needs, like if you need to limit the domain that can be used, you can easily override it by providing your own validation logic.\n\nThe validator must be callable that accepts a single parameter of type `str` and returns a value of type `bool`. Validator type: ```Callable[[str], bool]```\n\n```python\nfrom manokit import Email\n\ndef better_email_validator(addr: str) -\u003e bool:\n    return addr.endswith(\"@our_company.com\")\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"you@our_company.com\", password=\"manokit_is_cool\")\nemail.set_custom_email_validator(better_email_validator)\nemail.add_recipient(\"buddy@our_company.com\") # This will pass\nemail.add_bcc(\"spy@rival_corp.com\") # This will raise an exception\n```\nManokit also implements validation scopes. That means that, if you want to apply your custom validator only to certain parts, e.g. only to people who are BCC'd into the email, you can do it.\n```python\nfrom manokit import Email\n\ndef check_who_is_in_bcc(addr: str) -\u003e bool:\n    return addr.endswith(\"@our_company.com\")\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"you@our_company.com\", password=\"manokit_is_cool\")\nemail.set_custom_email_validator(check_who_is_in_bcc, scopes=[\"bcc\"])\nemail.add_recipient(\"client@clientperonal.org\") # This will pass\nemail.add_cc(\"clientswife@gmail.com\") # This will also pass\nemail.add_bcc(\"spy@rival_corp.com\") # This will raise an exception\n```\nAvailable scopes:\n- `all` -- apply your validation rules to all addresses. This is the default option used by Manokit\n- `author` -- apply your validation rules only to the sender's email. This validator will be applied during `login()`, so the setter needs to be called before that\n- `recipients` -- apply your validation rules only to recipients' addresses\n- `cc` -- apply your validation rules only to addresses that will be CC'd into the email\n- `bcc` -- apply your validation rules only to addresses that will be BCC'd into the email\n#### Adding attachments\nSometimes we need to send an email with a file attached to it. To attach the file to your email, simply call the `add_attachment` function and provide a path to the file.\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"boss@examplecorp.com\")\nemail.add_attachment(\"./reports/quarterly_q3_q4.pdf\")\n\nemail.logout()\n```\nJust as with `add_recipient`, `add_bcc` and `add_cc`, the `add_attachment` function adds one file at a time.\n\nIf an attachment has already been added, or if the size of the file being attach is 0, the function will have no effect.\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"boss@examplecorp.com\")\nemail.add_attachment(\"./reports/empty_report.pdf\")\n\nprint(len(email.attachments)) # Output: 0\n\nemail.logout()\n```\n#### Attachment size limit\nBy default, Manokit limits the combined size of the attachments to 25 MB (can be adjusted during the [Initialization](#initialization)).\n\nManokit also maintains an internal counter of how much space is available for future attachments.\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587, filesize_limit=100)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"boss@examplecorp.com\")\nemail.add_attachment(\"./reports/40kb_report.txt\")\n\nprint(email.available_filesize) # Output: 60\n\nemail.logout()\n```\nIf the attachment's size exceeds the limit, an [`AttachmentError`](#attachmenterror) will be raised.\n\n#### Sending an email\nTo send an email, just call `send()`\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(username=\"manokit@gmail.com\", password=\"manokit_is_cool\")\nemail.add_recipient(\"buddy@examplecorp.com\")\nemail.add_cc(\"buddy@examplecorp.com\")\n\nemail.send()\n\nemail.logout()\n```\nThis function can raise an [`EmailError`](#emailerror) if no recipients are defined or there was a problem while sending an email.\n\n#### Method chaining\nManokit's functions support method chaining\n```python\nfrom manokit import Email\n\nemail = Email(\"smtp.gmail.com\", 587)\nemail.login(\n    username=\"manokit@gmail.com\", \n    password=\"manokit_is_cool\",\n    ).add_recipient(\"buddy@examplecorp.com\")\n    .add_cc(\"buddy@examplecorp.com\")\n    .send()\n    .logout()\n```\nThe `logout()` function, however, is considered a logical endpoint, and thus does not support method chaining. In other words, the `logout()` function must be the last to be called.\n\n### Exceptions\n\n#### NotAValidEmailAddressError\nThis exception is raised when the email address fails validation.\n\nFunctions that can raise it:\n- `login()`\n- `add_recipient()`\n- `add_cc()`\n- `add_bcc()`\n\n#### EmailError\nThis exception is raised when there is a problem with the email itself. For now this exception is only raised by the `send()` function if there is no recipients or if there was a problem with sending an email\n\n#### AttachmentError\nThis exception is raised when there is a problem with email's attachments. for now this exception is only raised by the `add_attachment()` function if the path provided does not point to a file or the attachment's size is larger that the available space.\n\n## Changelog\n\nSee the full changelog [here](https://github.com/nickythelion/manokit/blob/master/CHANGELOG.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickythelion%2Fmanokit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnickythelion%2Fmanokit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnickythelion%2Fmanokit/lists"}