# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['mailers',
 'mailers.encrypters',
 'mailers.plugins',
 'mailers.signers',
 'mailers.transports']

package_data = \
{'': ['*']}

install_requires = \
['aiosmtplib>=1.1.6,<2.0.0', 'anyio>=3.3.0,<4.0.0']

setup_kwargs = {
    'name': 'mailers',
    'version': '2.0.0',
    'description': 'Email delivery for asyncio.',
    'long_description': '# Mailers for asyncio\n\n![PyPI](https://img.shields.io/pypi/v/mailers)\n![GitHub Workflow Status](https://img.shields.io/github/workflow/status/alex-oleshkevich/mailers/Lint)\n![GitHub](https://img.shields.io/github/license/alex-oleshkevich/mailers)\n![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/pypi/mailers)\n![PyPI - Downloads](https://img.shields.io/pypi/dm/mailers)\n![GitHub Release Date](https://img.shields.io/github/release-date/alex-oleshkevich/mailers)\n![Lines of code](https://img.shields.io/tokei/lines/github/alex-oleshkevich/mailers)\n\n## Features\n\n* fully typed\n* full utf-8 support\n* async and sync sending\n* pluggable transports\n* multiple built-in transports including: SMTP, file, null, in-memory, streaming, and console.\n* plugin system\n* embeddables\n* attachments (with async and sync interfaces)\n* message signing via Signer interface (DKIM bundled)\n* message encryption via Encrypter interface\n* trio support via anyio\n* fallback transports\n* global From address\n* templated emails\n\n## Usage\n\n```bash\npip install mailers\n```\n\n```python\nfrom mailers import create_mailer, Email\n\nmessage = Email(to=\'user@localhost\', from_address=\'from@localhost\', subject=\'Hello\', text=\'World!\')\nmailer = create_mailer(\'smtp://user:password@localhost:25?timeout=2\')\nawait mailer.send(message)\n```\n\nYou can also send to multiple recipients by passing an iterable int `to` argument:\n\n```python\nmessage = Email(to=[\'user@localhost\', \'user2@localhost\', \'user@localhost\'], ...)\n```\n\nalso you can change addresses any time you want:\n\n```python\nmessage.to.add(\'anotheruser@example.com\', \'me@example.com\')\n```\n\nsame rule applies to `to`, `from_address`, `cc`, `bcc`, `reply_to` fields.\n\n## Compose messages\n\nThe arguments and methods of `Email ` class are self-explanatory so here is an kick-start example:\n\n```python\nfrom mailers import Email\n\nmessage = Email(\n    to=\'user@localhost\',\n    from_address=\'from@example.tld\',\n    cc=\'cc@example.com\',\n    bcc=[\'bcc@example.com\'],\n    text=\'Hello world!\',\n    html=\'<b>Hello world!</b>\',\n)\n```\n\n`cc`, `bcc`, `to`, `reply_to` can be either strings or lists of strings.\n\n### Global From address\n\nInstead of setting "From" header in every message, you can set it mailer-wide. Use `from_address` argument of Mailer\nclass:\n\n```python\nmailer = Mailer(from_address="sender@localhost")\n```\n\nThe mailer will set From header with the given value to all messages that do not container From or Sender headers.\n\n## Using templates\n\nYou can use any template engine with a special email class called `TemplatedEmail`. This class extends `Email` with\nfollowing arguments:\n\n* `html_template`  - a template for use in HTML part\n* `text_template`  - a template for use in text part\n* `context` - a template context\n\nThen, you need to use appropriate plugin that can render the email message.\n\nOut of the box, we provide a Jinja adapter.\n\n### Use Jinja2 engine\n\nYou can use Jinja template engine to render your emails. Add `JinjaRendererPlugin` with a\npreconfigured `jinja2.Environment` instance. Then, use `mailers.TemplatedEmail` instead of `mailers.Email` to configure\ntemplated mail.\n\n```python\nimport jinja2\n\nfrom mailers import Mailer, TemplatedEmail\nfrom mailers.plugins.jinja_renderer import JinjaRendererPlugin\n\nenv = jinja2.Environment(loader=jinja2.FileSystemLoader([\'templates\']))\nmailer = Mailer(plugins=[JinjaRendererPlugin])\n\nemail = TemplatedEmail(subject=\'Hello\', text_template=\'mail.txt\', html_template=\'mail.html\', context={\'user\': \'root\'})\nmailer.send(email)\n```\n\n## Attachments\n\nUse `attach`, `attach_from_path`, `attach_from_path_sync` methods to attach files.\n\n```python\nfrom mailers import Email\n\nmessage = Email(to=\'user@localhost\', from_address=\'from@example.tld\', text=\'Hello world!\')\n\n# attachments can be added on demand\nawait message.attach_from_path(\'file.txt\')\n\n# or use blocking sync version\nmessage.attach_from_path_sync(\'file.txt\')\n\n# attach from variable\nmessage.attach(\'CONTENTS\', \'file.txt\', \'text/plain\')\n```\n\n## Embedding files\n\nIn the same way as with attachments, you can inline files into your messages. This is commonly used to display embedded\nimages in the HTML body. Here are method you can use `embed`, `embed_from_path`, `embed_from_path_sync`.\n\n```python\nfrom mailers import Email\n\nmessage = Email(\n    to=\'user@localhost\',\n    from_address=\'from@example.tld\',\n    html=\'Render me <img src="cid:img1">\',\n)\n\nawait message.embed_from_path(path=\'/path/to/image.png\', name=\'img1\')\n```\n\nNote, that you have to add HTML part to embed files. Otherwise, they will be ignored.\n\n## Message signatures\n\nYou can sign messages (e.g. with DKIM) by passing `signer` argument to the `Mailer` instance.\n\n```python\nsigner = MySigner()\nmailer = Mailer(..., signer=signer)\n\n# or\nmailer = create_mailer(..., signer=signer)\n```\n\n### DKIM signing\n\nYou may wish to add DKIM signature to your messages to prevent them from being put into the spam folder.\n\nNote, you need to install [`dkimpy`](https://pypi.org/project/dkimpy/) package before using this feature.\n\n```python\nfrom mailers import create_mailer\nfrom mailers.signers.dkim import DKIMSigner\n\nsigner = DKIMSigner(selector=\'default\', private_key_path=\'/path/to/key.pem\')\n\n# or you can put key content using private_key argument\nsigner = DKIMSigner(selector=\'default\', private_key=\'PRIVATE KEY GOES here...\')\n\nmailer = create_mailer(\'smtp://\', signer=signer)\n```\n\nNow all outgoing messages will be signed with DKIM method.\n\nThe plugin signs "From", "To", "Subject" headers by default. Use "headers" argument to override it.\n\n## Custom signers\n\nExtend `mailers.Signer` class and implement `sign` method:\n\n```python\nfrom email.message import Message\nfrom mailers import Signer\n\n\nclass MySigner(Signer):\n    def sign(self, message: Message) -> Message:\n        # message signing code here...\n        return message\n```\n\n## Encrypters\n\nWhen encrypting a message, the entire message (including attachments) is encrypted using a certificate. Therefore, only\nthe recipients that have the corresponding private key can read the original message contents.\n\n````python\nencrypter = MyEncrypter()\nmailer = Mailer(..., encrypter=encrypter)\n````\n\nNow all message content will be encrypted.\n\n## Custom encrypters\n\nExtend `mailers.Encrypter` class and implement `encrypt` method:\n\n```python\nfrom email.message import Message\nfrom mailers import Encrypter\n\n\nclass MyEncrypter(Encrypter):\n    def encrypt(self, message: Message) -> Message:\n        # message encrypting code here...\n        return message\n```\n\n## High Availability\n\nYou can pass multiples transports to the Mailer instance and it will iterate over them asking each to send a message. By\ndefault, the first transport is used but if it fails to send the message, the mailer will retry sending with the next\ntransport in the chain.\n\n```python\nmailer = Mailer([transport1, transport2, ..., transportN])\n```\n\n## Plugins\n\nPlugins let you inspect and modify outgoing messages before or after they are sent. The plugin is a class that\nimplements `mailers.plugins.Plugin` protocol. Plugins are added to mailers via `plugins` argument.\n\nBelow you see an example plugin:\n\n```python\nfrom email.message import Message\n\nfrom mailers import BasePlugin, create_mailer, Mailer, SentMessages\n\n\nclass PrintPlugin(BasePlugin):\n\n    async def on_before_send(self, message: Message) -> None:\n        print(\'sending message %s.\' % message)\n\n    async def on_after_send(self, message: Message, sent_messages: SentMessages) -> None:\n        print(\'message has been sent %s.\' % message)\n\n    async def on_send_error(self, message: Message, sent_messages: SentMessages) -> None:\n        print(\'error sending message %s.\' % message)\n\n\nmailer = Mailer(plugins=[PrintPlugin()])\n\n# or if you use create_mailer shortcut\nmailer = create_mailer(plugins=[PrintPlugin()])\n```\n\n## Transports\n\n### SMTP transport\n\nSend messages via third-party SMTP servers.\n\n**Class:** `mailers.transports.SMTPTransport`\n**directory** `smtp://user:pass@hostname:port?timeout=&use_tls=1`\n**Options:**\n\n* `host` (string, default "localhost") - SMTP server host\n* `port` (string, default "25") - SMTP server port\n* `user` (string) - SMTP server login\n* `password` (string) - SMTP server login password\n* `use_tls` (string, choices: "yes", "1", "on", "true") - use TLS\n* `timeout` (int) - connection timeout\n* `cert_file` (string) - path to certificate file\n* `key_file` (string) - path to key file\n\n### File transport\n\nWrite outgoing messages into a directory in EML format.\n\n**Class:** `mailers.transports.FileTransport`\n**DSN:** `file:///tmp/mails`\n**Options:**\n\n* `directory` (string) path to a directory\n\n### Null transport\n\nDiscards outgoing messages. Takes no action on send.\n\n**Class:** `mailers.transports.NullTransport`\n**DSN:** `null://`\n\n### Memory transport\n\nKeeps all outgoing messages in memory. Good for testing.\n\n**Class:** `mailers.transports.InMemoryTransport`\n**DSN:** `memory://`\n**Options:**\n\n* `storage` (list of strings) - outgoing message container\n\nYou can access the mailbox via ".mailbox" attribute.\n\nExample:\n\n```python\nfrom mailers import Mailer, InMemoryTransport, Email\n\ntransport = InMemoryTransport([])\nmailer = Mailer(transport)\n\nawait mailer.send(Email(...))\nassert len(transport.mailbox) == 1  # here are all outgoing messages\n```\n\n### Streaming transport\n\nWrites all messages into a writable stream. Ok for local development.\n\n**Class:** `mailers.transports.StreamTransport`\n**DSN:** unsupported\n**Options:**\n\n* `output` (typing.IO) - a writable stream\n\nExample:\n\n```python\nimport io\nfrom mailers import Mailer, StreamTransport\n\ntransport = StreamTransport(output=io.StringIO())\nmailer = Mailer(transport)\n```\n\n### Console transport\n\nThis is a preconfigured subclass of streaming transport. Writes to `sys.stderr` by default.\n\n**Class:** `mailers.transports.ConsoleTransport`\n**DSN:** `console://`\n**Options:**\n\n* `output` (typing.IO) - a writeable stream\n\n### Custom transports.\n\nEach transport must extend `mailers.transports.Transport` base class.\n\n```python\nimport typing as t\nfrom email.message import Message\nfrom mailers import Mailer, Transport, EmailURL, SentMessage\n\n\nclass PrintTransport(Transport):\n    @classmethod\n    def from_url(cls, url: t.Union[str, EmailURL]) -> t.Optional[Transport]:\n        # this method is optional,\n        # if your transport does not support instantiation from URL then return None here.\n        # returning None is the default behavior\n        return None\n\n    async def send(self, message: Message) -> SentMessage:\n        print(str(message))\n        return SentMessage(True, message, self)\n\n\nmailer = Mailer(PrintTransport())\n```\n\nThe library will call `Transport.from_url` when it needs to instantiate the transport instance from the URL. It is ok to\nreturn `None` as call result then the transport will be instantiated using construction without any arguments passed.\n\nOnce you have defined a new transport, register a URL protocol for it:\n\n```python\nadd_protocol_handler(\'print\', PrintTransport)\nmailer = Mailer(\'print://\')\n```\n',
    'author': 'alex.oleshkevich',
    'author_email': 'alex.oleshkevich@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/alex-oleshkevich/mailers',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'python_requires': '>=3.8,<4.0',
}


setup(**setup_kwargs)
