.. http://docutils.sourceforge.net/docs/user/rst/quickref.html
.. |nbsp| unicode:: 0xA0
:trim:
imap_tools 📧
=============
High level lib for work with email by IMAP:
- Basic message operations: fetch, uids, numbers
- Parsed email message attributes
- Query builder for search criteria
- Actions with emails: copy, delete, flag, move, append
- Actions with folders: list, set, get, create, exists, rename, subscribe, delete, status
- IDLE commands: start, poll, stop, wait
- Exceptions on failed IMAP operations
- No external dependencies, tested
.. image:: https://img.shields.io/pypi/dm/imap_tools.svg?style=social
=============== ================================================================================================
Python version 3.5+
License Apache-2.0
PyPI https://pypi.python.org/pypi/imap_tools/
RFC `IMAP4.1 <https://tools.ietf.org/html/rfc3501>`_,
`EMAIL <https://tools.ietf.org/html/rfc2822>`_,
`IMAP related RFCs <https://github.com/ikvk/imap_tools/blob/master/docs/IMAP_related_RFCs.txt>`_
Repo mirror https://gitflic.ru/project/ikvk/imap-tools
=============== ================================================================================================
.. contents::
Installation
------------
::
$ pip install imap-tools
Guide
-----
Basic
^^^^^
Info about lib are at: *this page*, docstrings, issues, pull requests, examples, source, stackoverflow.com
.. code-block:: python
from imap_tools import MailBox, AND
# Get date, subject and body len of all emails from INBOX folder
with MailBox('imap.mail.com').login('test@mail.com', 'pwd') as mailbox:
for msg in mailbox.fetch():
print(msg.date, msg.subject, len(msg.text or msg.html))
`Description of this^ example <https://github.com/ikvk/imap_tools/blob/master/examples/basic.py>`_.
MailBox, MailBoxTls, MailBoxUnencrypted - for create mailbox client. `TLS example <https://github.com/ikvk/imap_tools/blob/master/examples/tls.py>`_.
BaseMailBox.<auth> - login, login_utf8, xoauth2, logout - authentication functions, they support context manager.
BaseMailBox.fetch - first searches email uids by criteria in current folder, then fetch and yields `MailMessage <#email-attributes>`_, args:
* *criteria* = 'ALL', message search criteria, `query builder <#search-criteria>`_
* *charset* = 'US-ASCII', indicates charset of the strings that appear in the search criteria. See rfc2978
* *limit* = None, limit on the number of read emails, useful for actions with a large number of messages, like "move". May be int or slice.
* *mark_seen* = True, mark emails as seen on fetch
* *reverse* = False, in order from the larger date to the smaller
* *headers_only* = False, get only email headers (without text, html, attachments)
* *bulk* = False, False - fetch each message separately per N commands - low memory consumption, slow; True - fetch all messages per 1 command - high memory consumption, fast; int - fetch all messages by bulks of the specified size, for 20 messages and bulk=5 -> 4 commands
* *sort* = None, criteria for sort messages on server, use SortCriteria constants. Charset arg is important for sort
BaseMailBox.uids - search mailbox for matching message uids in current folder, returns [str | None], None when MailMessage.from_bytes used, args:
* *criteria* = 'ALL', message search criteria, `query builder <#search-criteria>`_
* *charset* = 'US-ASCII', indicates charset of the strings that appear in the search criteria. See rfc2978
* *sort* = None, criteria for sort messages on server, use SortCriteria constants. Charset arg is important for sort
BaseMailBox.<action> - `copy, move, delete, flag, append <#actions-with-emails>`_
BaseMailBox.folder - `folder manager <#actions-with-folders>`_
BaseMailBox.idle - `idle manager <#idle-workflow>`_
BaseMailBox.numbers - search mailbox for matching message numbers in current folder, returns [str]
BaseMailBox.numbers_to_uids - Get message uids by message numbers, returns [str]
BaseMailBox.client - imaplib.IMAP4/IMAP4_SSL client instance.
Email attributes
^^^^^^^^^^^^^^^^
Email has 2 basic body variants: text and html. Sender can choose to include: one, other, both or neither(rare).
MailMessage and MailAttachment public attributes are cached by functools.lru_cache
.. code-block:: python
for msg in mailbox.fetch(): # generator: imap_tools.MailMessage
msg.uid # str | None: '123'
msg.subject # str: 'some subject 你 привет'
msg.from_ # str: 'Bartölke@ya.ru'
msg.to # tuple: ('iam@goo.ru', 'friend@ya.ru', )
msg.cc # tuple: ('cc@mail.ru', )
msg.bcc # tuple: ('bcc@mail.ru', )
msg.reply_to # tuple: ('reply_to@mail.ru', )
msg.date # datetime.datetime: 1900-1-1 for unparsed, may be naive or with tzinfo
msg.date_str # str: original date - 'Tue, 03 Jan 2017 22:26:59 +0500'
msg.text # str: 'Hello 你 Привет'
msg.html # str: '<b>Hello 你 Привет</b>'
msg.flags # tuple: ('\\Seen', '\\Flagged', 'ENCRYPTED')
msg.headers # dict: {'received': ('from 1.m.ru', 'from 2.m.ru'), 'anti-virus': ('Clean',)}
msg.size_rfc822 # int: 20664 bytes - size info from server (*useful with headers_only arg)
msg.size # int: 20377 bytes - size of received message
for att in msg.attachments: # list: imap_tools.MailAttachment
att.filename # str: 'cat.jpg'
att.payload # bytes: b'\xff\xd8\xff\xe0\'
att.content_id # str: 'part45.06020801.00060008@mail.ru'
att.content_type # str: 'image/jpeg'
att.content_disposition # str: 'inline'
att.part # email.message.Message: original object
att.size # int: 17361 bytes
msg.obj # email.message.Message: original object
msg.from_values # imap_tools.EmailAddress | None
msg.to_values # tuple: (imap_tools.EmailAddress,)
msg.cc_values # tuple: (imap_tools.EmailAddress,)
msg.bcc_values # tuple: (imap_tools.EmailAddress,)
msg.reply_to_values # tuple: (imap_tools.EmailAddress,)
# imap_tools.EmailAddress example:
# EmailAddress(name='Ya', email='im@ya.ru') # has "full" property = 'Ya <im@ya.ru>'
Search criteria
^^^^^^^^^^^^^^^
The *"criteria"* argument is used at *fetch, uids, numbers* methods of MailBox. Criteria can be of three types:
.. code-block:: python
from imap_tools import AND
mailbox.fetch(AND(subject='weather')) # query, the str-like object
mailbox.fetch('TEXT "hello"') # str
mailbox.fetch(b'TEXT "\xd1\x8f"') # bytes
Use *"charset"* argument for encode criteria to the desired encoding. If criteria is bytes - encoding will be ignored.
.. code-block:: python
mailbox.uids(A(subject='жёлтый'), charset='utf8')
Query builder implements all search logic described in `rfc3501 <https://tools.ietf.org/html/rfc3501#section-6.4.4>`_.
It uses this classes:
======== ===== ========================================== ======================================
Class Alias Description Arguments
======== ===== ========================================== ======================================
AND A Combine conditions by logical "AND" Search keys (see table below) | str
OR O Combine conditions by logical "OR" Search keys (see table below) | str
NOT N Invert the result of a logical expression AND/OR instances | str
Header H Header value for search by header key name: str, value: str
UidRange U UID range value for search by uid key start: str, end: str
======== ===== ========================================== ======================================
See `query examples <https://github.com/ikvk/imap_tools/blob/master/examples/search.py>`_. A few examples:
.. code-block:: python
from imap_tools import A, AND, OR, NOT
# AND
A(text='hello', new=True) # '(TEXT "hello" NEW)'
# OR
OR(text='hello', date=datetime.date(2000, 3, 15)) # '(OR TEXT "hello" ON 15-Mar-2000)'
# NOT
NOT(text='hello', new=True) # 'NOT (TEXT "hello" NEW)'
# complex
A(OR(from_='from@ya.ru', text='"the text"'), NOT(OR(A(answered=False), A(new=True))), to='to@ya.ru')
# python note: you can't do: A(text='two', NOT(subject='one'))
A(NOT(subject='one'), text='two') # use kwargs after logic classes (args)
Server side search notes:
* For string search keys a message matches if the string is a substring of the field. The matching is case-insensitive.
* When searching by dates - email's time and timezone are disregarding.
Search key table. Key types marked with `*` can accepts a sequence of values like list, tuple, set or generator.
============= =============== ====================== ================================================================
Key Types Results Description
============= =============== ====================== ================================================================
answered bool `ANSWERED/UNANSWERED` with/without the Answered flag
seen bool `SEEN/UNSEEN` with/without the Seen flag
flagged bool `FLAGGED/UNFLAGGED` with/without the Flagged flag
draft bool `DRAFT/UNDRAFT` with/without the Draft flag
deleted bool `DELETED/UNDELETED` with/without the Deleted flag
keyword str* KEYWORD KEY with the specified keyword flag
no_keyword str* UNKEYWORD KEY without the specified keyword flag
`from_` str* FROM `"from@ya.ru"` contain specified str in envelope struct's FROM field
to str* TO `"to@ya.ru"` contain specified str in envelope struct's TO field
subject str* SUBJECT "hello" contain specified str in envelope struct's SUBJECT field
body str* BODY "some_key" contain specified str in body of the message
text str* TEXT "some_key" contain specified str in header or body of the message
bcc str* BCC `"bcc@ya.ru"` contain specified str in envelope struct's BCC field
cc str* CC `"cc@ya.ru"` contain specified str in envelope struct's CC field
date datetime.date* ON 15-Mar-2000 internal date is within specified date
date_gte datetime.date* SINCE 15-Mar-2000 internal date is within or later than the specified date
date_lt datetime.date* BEFORE 15-Mar-2000 internal date is earlier than the specified date
sent_date datetime.date* SENTON 15-Mar-2000 rfc2822 Date: header is within the specified date
sent_date_gte datetime.date* SENTSINCE 15-Mar-2000 rfc2822 Date: header is within or later than the specified date
sent_date_lt datetime.date* SENTBEFORE 1-Mar-2000 rfc2822 Date: header is earlier than the specified date
size_gt int >= 0 LARGER 1024 rfc2822 size larger than specified number of octets
size_lt int >= 0 SMALLER 512 rfc2822 size smaller than specified number of octets
new True NEW have the Recent flag set but not the Seen flag
old True OLD do not have the Recent flag set
recent True RECENT have the Recent flag set
all True ALL all, criteria by default
uid iter(str)/str/U UID 1,2,17 corresponding to the specified unique identifier set
header H(str, str)* HEADER "A-Spam" "5.8" have a header that contains the specified str in the text
gmail_label str* X-GM-LABELS "label1" have this gmail label
============= =============== ====================== ================================================================
Actions with emails
^^^^^^^^^^^^^^^^^^^
First of all read about UID `at rfc3501 <https://tools.ietf.org/html/rfc3501#section-2.3.1.1>`_.
Action's uid_list arg may takes:
* str, that is comma separated uids
* Sequence, that contains str uids
To get uids, use the maibox methods: uids, fetch.
For actions with a large number of messages imap command may be too large and will cause exception at server side,
use 'limit' argument for fetch in this case.
.. code-block:: python
with MailBox('imap.mail.com').login('test@mail.com', 'pwd', initial_folder='INBOX') as mailbox:
# COPY messages with uid in 23,27 from current folder to folder1
mailbox.copy('23,27', 'folder1')
# MOVE all messages from current folder to INBOX/folder2
mailbox.move(mailbox.uids(), 'INBOX/folder2')
# DELETE messages with 'cat' word in its html from current folder
mailbox.delete([msg.uid for msg in mailbox.fetch() if 'cat' in msg.html])
# FLAG unseen messages in current folder as \Seen, \Flagged and TAG1
flags = (imap_tools.MailMessageFlags.SEEN, imap_tools.MailMessageFlags.FLAGGED, 'TAG1')
mailbox.flag(mailbox.uids(AND(seen=False)), flags, True)
# APPEND: add message to mailbox directly, to INBOX folder with \Seen flag and now date
with open('/tmp/message.eml', 'rb') as f:
msg = imap_tools.MailMessage.from_bytes(f.read()) # *or use bytes instead MailMessage
mailbox.append(msg, 'INBOX', dt=None, flag_set=[imap_tools.MailMessageFlags.SEEN])
Actions with folders
^^^^^^^^^^^^^^^^^^^^
BaseMailBox.login/xoauth2 has initial_folder arg, that is "INBOX" by default, use None for not set folder on login.
.. code-block:: python
with MailBox('imap.mail.com').login('test@mail.com', 'pwd') as mailbox:
# LIST: get all subfolders of the specified folder (root by default)
for f in mailbox.folder.list('INBOX'):
print(f) # FolderInfo(name='INBOX|cats', delim='|', flags=('\\Unmarked', '\\HasChildren'))
# SET: select folder for work
mailbox.folder.set('INBOX')
# GET: get selected folder
current_folder = mailbox.folder.get()
# CREATE: create new folder
mailbox.folder.create('INBOX|folder1')
# EXISTS: check is folder exists (shortcut for list)
is_exists = mailbox.folder.exists('INBOX|folder1')
# RENAME: set new name to folder
mailbox.folder.rename('folder3', 'folder4')
# SUBSCRIBE: subscribe/unsubscribe to folder
mailbox.folder.subscribe('INBOX|папка два', True)
# DELETE: delete folder
mailbox.folder.delete('folder4')
# STATUS: get folder status info
stat = mailbox.folder.status('some_folder')
print(stat) # {'MESSAGES': 41, 'RECENT': 0, 'UIDNEXT': 11996, 'UIDVALIDITY': 1, 'UNSEEN': 5}
IDLE workflow
^^^^^^^^^^^^^
IDLE logic are in mailbox.idle manager, its methods are in the table below:
======== ============================================================================== ================================
Method Description Arguments
======== ============================================================================== ================================
start Switch on mailbox IDLE mode
poll Poll for IDLE responses timeout: |nbsp| Optional[float]
stop Switch off mailbox IDLE mode
wait Switch on IDLE, poll responses, switch off IDLE on response, return responses timeout: |nbsp| Optional[float]
======== ============================================================================== ================================
.. code-block:: python
from imap_tools import MailBox, A
# waiting for updates 60 sec, print unseen immediately if any update
with MailBox('imap.my.moon').login('acc', 'pwd', 'INBOX') as mailbox:
responses = mailbox.idle.wait(timeout=60)
if responses:
for msg in mailbox.fetch(A(seen=False)):
print(msg.date, msg.subject)
else:
print('no updates in 60 sec')
Read docstrings and see `detailed examples <https://github.com/ikvk/imap_tools/blob/master/examples/idle.py>`_.
Exceptions
^^^^^^^^^^
Most lib server actions raises exception if result is marked as not success.
Custom lib exceptions here: `errors.py <https://github.com/ikvk/imap_tools/blob/master/imap_tools/errors.py>`_.
Release notes
-------------
History of important changes: `release_notes.rst <https://github.com/ikvk/imap_tools/blob/master/docs/release_notes.rst>`_
Contribute
----------
If you found a bug or have a question, then:
1. Look for answer at: this page, issues, pull requests, examples, source, RFCs, stackoverflow.com, internet.
2. And only then - create merge request or issue.
Reasons
-------
- Excessive low level of `imaplib` library.
- Other libraries contain various shortcomings or not convenient.
- Open source projects make world better.
Thanks
------
Big thanks to people who helped develop this library:
`shilkazx <https://github.com/shilkazx>`_,
`somepad <https://github.com/somepad>`_,
`0xThiebaut <https://github.com/0xThiebaut>`_,
`TpyoKnig <https://github.com/TpyoKnig>`_,
`parchd-1 <https://github.com/parchd-1>`_,
`dojasoncom <https://github.com/dojasoncom>`_,
`RandomStrangerOnTheInternet <https://github.com/RandomStrangerOnTheInternet>`_,
`jonnyarnold <https://github.com/jonnyarnold>`_,
`Mitrich3000 <https://github.com/Mitrich3000>`_,
`audemed44 <https://github.com/audemed44>`_,
`mkalioby <https://github.com/mkalioby>`_,
`atlas0fd00m <https://github.com/atlas0fd00m>`_,
`unqx <https://github.com/unqx>`_,
`daitangio <https://github.com/daitangio>`_,
`upils <https://github.com/upils>`_,
`Foosec <https://github.com/Foosec>`_,
`frispete <https://github.com/frispete>`_,
`PH89 <https://github.com/PH89>`_,
`amarkham09 <https://github.com/amarkham09>`_,
`nixCodeX <https://github.com/nixCodeX>`_,
`backelj <https://github.com/backelj>`_,
`ohayak <https://github.com/ohayak>`_,
`mwherman95926 <https://github.com/mwherman95926>`_,
`andyfensham <https://github.com/andyfensham>`_,
`mike-code <https://github.com/mike-code>`_,
`aknrdureegaesr <https://github.com/aknrdureegaesr>`_,
`ktulinger <https://github.com/ktulinger>`_,
`SamGenTLEManKaka <https://github.com/SamGenTLEManKaka>`_,
`devkral <https://github.com/devkral>`_,
`tnusraddinov <https://github.com/tnusraddinov>`_,
`thepeshka <https://github.com/thepeshka>`_,
`shofstet <https://github.com/shofstet>`_,
`the7erm <https://github.com/the7erm>`_,
`c0da <https://github.com/c0da>`_,
`dev4max <https://github.com/dev4max>`_,
`ascheucher <https://github.com/ascheucher>`_,
`Borutia <https://github.com/Borutia>`_,
`nathan30 <https://github.com/nathan30>`_,
`daniel55411 <https://github.com/daniel55411>`_,
`rcarmo <https://github.com/rcarmo>`_,
`bhernacki <https://github.com/bhernacki>`_,
`ilep <https://github.com/ilep>`_,
`ThKue <https://github.com/ThKue>`_,
`repodiac <https://github.com/repodiac>`_,
`tiuub <https://github.com/tiuub>`_,
`Yannik <https://github.com/Yannik>`_,
`pete312 <https://github.com/pete312>`_,
`edkedk99 <https://github.com/edkedk99>`_,
`UlisseMini <https://github.com/UlisseMini>`_,
`Nicarex <https://github.com/Nicarex>`_,
`RanjithNair1980 <https://github.com/RanjithNair1980>`_,
`NickC-NZ <https://github.com/NickC-NZ>`_,
`mweinelt <https://github.com/mweinelt>`_,
`lucbouge <https://github.com/lucbouge>`_,
`JacquelinCharbonnel <https://github.com/JacquelinCharbonnel>`_,
`stumpylog <https://github.com/stumpylog>`_,
`dimitrisstr <https://github.com/dimitrisstr>`_,
`abionics <https://github.com/abionics>`_,
`link2xt <https://github.com/link2xt>`_,
`Docpart <https://github.com/Docpart>`_,
`meetttttt <https://github.com/meetttttt>`_,
`sapristi <https://github.com/sapristi>`_,
`thomwiggers <https://github.com/thomwiggers>`_,
`histogal <https://github.com/histogal>`_,
`K900 <https://github.com/K900>`_,
`homoLudenus <https://github.com/homoLudenus>`_,
`sphh <https://github.com/sphh>`_
Help the project
----------------
1. Found a bug or figure out how to improve the library - open issue or merge request 🎯
2. Do not know how to improve library - try to help other open projects that you use ✋
3. Nowhere to put your money - spend it on your family, friends, loved ones, or people around you 💰
4. Star the project ⭐
Raw data
{
"_id": null,
"home_page": "https://github.com/ikvk/imap_tools",
"name": "imap-tools",
"maintainer": null,
"docs_url": null,
"requires_python": null,
"maintainer_email": null,
"keywords": "imap, imap-client, python3, python, email",
"author": "Vladimir Kaukin",
"author_email": "KaukinVK@ya.ru",
"download_url": "https://files.pythonhosted.org/packages/0b/bd/f7451edf9d9c26969fd43618b3ae7042b51b8ba545a13227a237f7b3ab47/imap-tools-1.8.0.tar.gz",
"platform": null,
"description": ".. http://docutils.sourceforge.net/docs/user/rst/quickref.html\n\n.. |nbsp| unicode:: 0xA0\n :trim:\n\nimap_tools \ud83d\udce7\n=============\n\nHigh level lib for work with email by IMAP:\n\n- Basic message operations: fetch, uids, numbers\n- Parsed email message attributes\n- Query builder for search criteria\n- Actions with emails: copy, delete, flag, move, append\n- Actions with folders: list, set, get, create, exists, rename, subscribe, delete, status\n- IDLE commands: start, poll, stop, wait\n- Exceptions on failed IMAP operations\n- No external dependencies, tested\n\n.. image:: https://img.shields.io/pypi/dm/imap_tools.svg?style=social\n\n=============== ================================================================================================\nPython version 3.5+\nLicense Apache-2.0\nPyPI https://pypi.python.org/pypi/imap_tools/\nRFC `IMAP4.1 <https://tools.ietf.org/html/rfc3501>`_,\n `EMAIL <https://tools.ietf.org/html/rfc2822>`_,\n `IMAP related RFCs <https://github.com/ikvk/imap_tools/blob/master/docs/IMAP_related_RFCs.txt>`_\nRepo mirror https://gitflic.ru/project/ikvk/imap-tools\n=============== ================================================================================================\n\n.. contents::\n\nInstallation\n------------\n::\n\n $ pip install imap-tools\n\nGuide\n-----\n\nBasic\n^^^^^\n\nInfo about lib are at: *this page*, docstrings, issues, pull requests, examples, source, stackoverflow.com\n\n.. code-block:: python\n\n from imap_tools import MailBox, AND\n\n # Get date, subject and body len of all emails from INBOX folder\n with MailBox('imap.mail.com').login('test@mail.com', 'pwd') as mailbox:\n for msg in mailbox.fetch():\n print(msg.date, msg.subject, len(msg.text or msg.html))\n\n`Description of this^ example <https://github.com/ikvk/imap_tools/blob/master/examples/basic.py>`_.\n\nMailBox, MailBoxTls, MailBoxUnencrypted - for create mailbox client. `TLS example <https://github.com/ikvk/imap_tools/blob/master/examples/tls.py>`_.\n\nBaseMailBox.<auth> - login, login_utf8, xoauth2, logout - authentication functions, they support context manager.\n\nBaseMailBox.fetch - first searches email uids by criteria in current folder, then fetch and yields `MailMessage <#email-attributes>`_, args:\n\n* *criteria* = 'ALL', message search criteria, `query builder <#search-criteria>`_\n* *charset* = 'US-ASCII', indicates charset of the strings that appear in the search criteria. See rfc2978\n* *limit* = None, limit on the number of read emails, useful for actions with a large number of messages, like \"move\". May be int or slice.\n* *mark_seen* = True, mark emails as seen on fetch\n* *reverse* = False, in order from the larger date to the smaller\n* *headers_only* = False, get only email headers (without text, html, attachments)\n* *bulk* = False, False - fetch each message separately per N commands - low memory consumption, slow; True - fetch all messages per 1 command - high memory consumption, fast; int - fetch all messages by bulks of the specified size, for 20 messages and bulk=5 -> 4 commands\n* *sort* = None, criteria for sort messages on server, use SortCriteria constants. Charset arg is important for sort\n\nBaseMailBox.uids - search mailbox for matching message uids in current folder, returns [str | None], None when MailMessage.from_bytes used, args:\n\n* *criteria* = 'ALL', message search criteria, `query builder <#search-criteria>`_\n* *charset* = 'US-ASCII', indicates charset of the strings that appear in the search criteria. See rfc2978\n* *sort* = None, criteria for sort messages on server, use SortCriteria constants. Charset arg is important for sort\n\nBaseMailBox.<action> - `copy, move, delete, flag, append <#actions-with-emails>`_\n\nBaseMailBox.folder - `folder manager <#actions-with-folders>`_\n\nBaseMailBox.idle - `idle manager <#idle-workflow>`_\n\nBaseMailBox.numbers - search mailbox for matching message numbers in current folder, returns [str]\n\nBaseMailBox.numbers_to_uids - Get message uids by message numbers, returns [str]\n\nBaseMailBox.client - imaplib.IMAP4/IMAP4_SSL client instance.\n\nEmail attributes\n^^^^^^^^^^^^^^^^\n\nEmail has 2 basic body variants: text and html. Sender can choose to include: one, other, both or neither(rare).\n\nMailMessage and MailAttachment public attributes are cached by functools.lru_cache\n\n.. code-block:: python\n\n for msg in mailbox.fetch(): # generator: imap_tools.MailMessage\n msg.uid # str | None: '123'\n msg.subject # str: 'some subject \u4f60 \u043f\u0440\u0438\u0432\u0435\u0442'\n msg.from_ # str: 'Bart\u00f6lke@ya.ru'\n msg.to # tuple: ('iam@goo.ru', 'friend@ya.ru', )\n msg.cc # tuple: ('cc@mail.ru', )\n msg.bcc # tuple: ('bcc@mail.ru', )\n msg.reply_to # tuple: ('reply_to@mail.ru', )\n msg.date # datetime.datetime: 1900-1-1 for unparsed, may be naive or with tzinfo\n msg.date_str # str: original date - 'Tue, 03 Jan 2017 22:26:59 +0500'\n msg.text # str: 'Hello \u4f60 \u041f\u0440\u0438\u0432\u0435\u0442'\n msg.html # str: '<b>Hello \u4f60 \u041f\u0440\u0438\u0432\u0435\u0442</b>'\n msg.flags # tuple: ('\\\\Seen', '\\\\Flagged', 'ENCRYPTED')\n msg.headers # dict: {'received': ('from 1.m.ru', 'from 2.m.ru'), 'anti-virus': ('Clean',)}\n msg.size_rfc822 # int: 20664 bytes - size info from server (*useful with headers_only arg)\n msg.size # int: 20377 bytes - size of received message\n\n for att in msg.attachments: # list: imap_tools.MailAttachment\n att.filename # str: 'cat.jpg'\n att.payload # bytes: b'\\xff\\xd8\\xff\\xe0\\'\n att.content_id # str: 'part45.06020801.00060008@mail.ru'\n att.content_type # str: 'image/jpeg'\n att.content_disposition # str: 'inline'\n att.part # email.message.Message: original object\n att.size # int: 17361 bytes\n\n msg.obj # email.message.Message: original object\n msg.from_values # imap_tools.EmailAddress | None\n msg.to_values # tuple: (imap_tools.EmailAddress,)\n msg.cc_values # tuple: (imap_tools.EmailAddress,)\n msg.bcc_values # tuple: (imap_tools.EmailAddress,)\n msg.reply_to_values # tuple: (imap_tools.EmailAddress,)\n\n # imap_tools.EmailAddress example:\n # EmailAddress(name='Ya', email='im@ya.ru') # has \"full\" property = 'Ya <im@ya.ru>'\n\nSearch criteria\n^^^^^^^^^^^^^^^\n\nThe *\"criteria\"* argument is used at *fetch, uids, numbers* methods of MailBox. Criteria can be of three types:\n\n.. code-block:: python\n\n from imap_tools import AND\n\n mailbox.fetch(AND(subject='weather')) # query, the str-like object\n mailbox.fetch('TEXT \"hello\"') # str\n mailbox.fetch(b'TEXT \"\\xd1\\x8f\"') # bytes\n\nUse *\"charset\"* argument for encode criteria to the desired encoding. If criteria is bytes - encoding will be ignored.\n\n.. code-block:: python\n\n mailbox.uids(A(subject='\u0436\u0451\u043b\u0442\u044b\u0439'), charset='utf8')\n\nQuery builder implements all search logic described in `rfc3501 <https://tools.ietf.org/html/rfc3501#section-6.4.4>`_.\nIt uses this classes:\n\n======== ===== ========================================== ======================================\nClass Alias Description Arguments\n======== ===== ========================================== ======================================\nAND A Combine conditions by logical \"AND\" Search keys (see table below) | str\nOR O Combine conditions by logical \"OR\" Search keys (see table below) | str\nNOT N Invert the result of a logical expression AND/OR instances | str\nHeader H Header value for search by header key name: str, value: str\nUidRange U UID range value for search by uid key start: str, end: str\n======== ===== ========================================== ======================================\n\nSee `query examples <https://github.com/ikvk/imap_tools/blob/master/examples/search.py>`_. A few examples:\n\n.. code-block:: python\n\n from imap_tools import A, AND, OR, NOT\n # AND\n A(text='hello', new=True) # '(TEXT \"hello\" NEW)'\n # OR\n OR(text='hello', date=datetime.date(2000, 3, 15)) # '(OR TEXT \"hello\" ON 15-Mar-2000)'\n # NOT\n NOT(text='hello', new=True) # 'NOT (TEXT \"hello\" NEW)'\n # complex\n A(OR(from_='from@ya.ru', text='\"the text\"'), NOT(OR(A(answered=False), A(new=True))), to='to@ya.ru')\n # python note: you can't do: A(text='two', NOT(subject='one'))\n A(NOT(subject='one'), text='two') # use kwargs after logic classes (args)\n\nServer side search notes:\n\n* For string search keys a message matches if the string is a substring of the field. The matching is case-insensitive.\n* When searching by dates - email's time and timezone are disregarding.\n\nSearch key table. Key types marked with `*` can accepts a sequence of values like list, tuple, set or generator.\n\n============= =============== ====================== ================================================================\nKey Types Results Description\n============= =============== ====================== ================================================================\nanswered bool `ANSWERED/UNANSWERED` with/without the Answered flag\nseen bool `SEEN/UNSEEN` with/without the Seen flag\nflagged bool `FLAGGED/UNFLAGGED` with/without the Flagged flag\ndraft bool `DRAFT/UNDRAFT` with/without the Draft flag\ndeleted bool `DELETED/UNDELETED` with/without the Deleted flag\nkeyword str* KEYWORD KEY with the specified keyword flag\nno_keyword str* UNKEYWORD KEY without the specified keyword flag\n`from_` str* FROM `\"from@ya.ru\"` contain specified str in envelope struct's FROM field\nto str* TO `\"to@ya.ru\"` contain specified str in envelope struct's TO field\nsubject str* SUBJECT \"hello\" contain specified str in envelope struct's SUBJECT field\nbody str* BODY \"some_key\" contain specified str in body of the message\ntext str* TEXT \"some_key\" contain specified str in header or body of the message\nbcc str* BCC `\"bcc@ya.ru\"` contain specified str in envelope struct's BCC field\ncc str* CC `\"cc@ya.ru\"` contain specified str in envelope struct's CC field\ndate datetime.date* ON 15-Mar-2000 internal date is within specified date\ndate_gte datetime.date* SINCE 15-Mar-2000 internal date is within or later than the specified date\ndate_lt datetime.date* BEFORE 15-Mar-2000 internal date is earlier than the specified date\nsent_date datetime.date* SENTON 15-Mar-2000 rfc2822 Date: header is within the specified date\nsent_date_gte datetime.date* SENTSINCE 15-Mar-2000 rfc2822 Date: header is within or later than the specified date\nsent_date_lt datetime.date* SENTBEFORE 1-Mar-2000 rfc2822 Date: header is earlier than the specified date\nsize_gt int >= 0 LARGER 1024 rfc2822 size larger than specified number of octets\nsize_lt int >= 0 SMALLER 512 rfc2822 size smaller than specified number of octets\nnew True NEW have the Recent flag set but not the Seen flag\nold True OLD do not have the Recent flag set\nrecent True RECENT have the Recent flag set\nall True ALL all, criteria by default\nuid iter(str)/str/U UID 1,2,17 corresponding to the specified unique identifier set\nheader H(str, str)* HEADER \"A-Spam\" \"5.8\" have a header that contains the specified str in the text\ngmail_label str* X-GM-LABELS \"label1\" have this gmail label\n============= =============== ====================== ================================================================\n\nActions with emails\n^^^^^^^^^^^^^^^^^^^\n\nFirst of all read about UID `at rfc3501 <https://tools.ietf.org/html/rfc3501#section-2.3.1.1>`_.\n\nAction's uid_list arg may takes:\n\n* str, that is comma separated uids\n* Sequence, that contains str uids\n\nTo get uids, use the maibox methods: uids, fetch.\n\nFor actions with a large number of messages imap command may be too large and will cause exception at server side,\nuse 'limit' argument for fetch in this case.\n\n.. code-block:: python\n\n with MailBox('imap.mail.com').login('test@mail.com', 'pwd', initial_folder='INBOX') as mailbox:\n\n # COPY messages with uid in 23,27 from current folder to folder1\n mailbox.copy('23,27', 'folder1')\n\n # MOVE all messages from current folder to INBOX/folder2\n mailbox.move(mailbox.uids(), 'INBOX/folder2')\n\n # DELETE messages with 'cat' word in its html from current folder\n mailbox.delete([msg.uid for msg in mailbox.fetch() if 'cat' in msg.html])\n\n # FLAG unseen messages in current folder as \\Seen, \\Flagged and TAG1\n flags = (imap_tools.MailMessageFlags.SEEN, imap_tools.MailMessageFlags.FLAGGED, 'TAG1')\n mailbox.flag(mailbox.uids(AND(seen=False)), flags, True)\n\n # APPEND: add message to mailbox directly, to INBOX folder with \\Seen flag and now date\n with open('/tmp/message.eml', 'rb') as f:\n msg = imap_tools.MailMessage.from_bytes(f.read()) # *or use bytes instead MailMessage\n mailbox.append(msg, 'INBOX', dt=None, flag_set=[imap_tools.MailMessageFlags.SEEN])\n\nActions with folders\n^^^^^^^^^^^^^^^^^^^^\n\nBaseMailBox.login/xoauth2 has initial_folder arg, that is \"INBOX\" by default, use None for not set folder on login.\n\n.. code-block:: python\n\n with MailBox('imap.mail.com').login('test@mail.com', 'pwd') as mailbox:\n\n # LIST: get all subfolders of the specified folder (root by default)\n for f in mailbox.folder.list('INBOX'):\n print(f) # FolderInfo(name='INBOX|cats', delim='|', flags=('\\\\Unmarked', '\\\\HasChildren'))\n\n # SET: select folder for work\n mailbox.folder.set('INBOX')\n\n # GET: get selected folder\n current_folder = mailbox.folder.get()\n\n # CREATE: create new folder\n mailbox.folder.create('INBOX|folder1')\n\n # EXISTS: check is folder exists (shortcut for list)\n is_exists = mailbox.folder.exists('INBOX|folder1')\n\n # RENAME: set new name to folder\n mailbox.folder.rename('folder3', 'folder4')\n\n # SUBSCRIBE: subscribe/unsubscribe to folder\n mailbox.folder.subscribe('INBOX|\u043f\u0430\u043f\u043a\u0430 \u0434\u0432\u0430', True)\n\n # DELETE: delete folder\n mailbox.folder.delete('folder4')\n\n # STATUS: get folder status info\n stat = mailbox.folder.status('some_folder')\n print(stat) # {'MESSAGES': 41, 'RECENT': 0, 'UIDNEXT': 11996, 'UIDVALIDITY': 1, 'UNSEEN': 5}\n\nIDLE workflow\n^^^^^^^^^^^^^\n\nIDLE logic are in mailbox.idle manager, its methods are in the table below:\n\n======== ============================================================================== ================================\nMethod Description Arguments\n======== ============================================================================== ================================\nstart Switch on mailbox IDLE mode\npoll Poll for IDLE responses timeout: |nbsp| Optional[float]\nstop Switch off mailbox IDLE mode\nwait Switch on IDLE, poll responses, switch off IDLE on response, return responses timeout: |nbsp| Optional[float]\n======== ============================================================================== ================================\n\n.. code-block:: python\n\n from imap_tools import MailBox, A\n\n # waiting for updates 60 sec, print unseen immediately if any update\n with MailBox('imap.my.moon').login('acc', 'pwd', 'INBOX') as mailbox:\n responses = mailbox.idle.wait(timeout=60)\n if responses:\n for msg in mailbox.fetch(A(seen=False)):\n print(msg.date, msg.subject)\n else:\n print('no updates in 60 sec')\n\nRead docstrings and see `detailed examples <https://github.com/ikvk/imap_tools/blob/master/examples/idle.py>`_.\n\nExceptions\n^^^^^^^^^^\n\nMost lib server actions raises exception if result is marked as not success.\n\nCustom lib exceptions here: `errors.py <https://github.com/ikvk/imap_tools/blob/master/imap_tools/errors.py>`_.\n\nRelease notes\n-------------\n\nHistory of important changes: `release_notes.rst <https://github.com/ikvk/imap_tools/blob/master/docs/release_notes.rst>`_\n\nContribute\n----------\n\nIf you found a bug or have a question, then:\n\n1. Look for answer at: this page, issues, pull requests, examples, source, RFCs, stackoverflow.com, internet.\n2. And only then - create merge request or issue.\n\nReasons\n-------\n\n- Excessive low level of `imaplib` library.\n- Other libraries contain various shortcomings or not convenient.\n- Open source projects make world better.\n\nThanks\n------\n\nBig thanks to people who helped develop this library:\n\n`shilkazx <https://github.com/shilkazx>`_,\n`somepad <https://github.com/somepad>`_,\n`0xThiebaut <https://github.com/0xThiebaut>`_,\n`TpyoKnig <https://github.com/TpyoKnig>`_,\n`parchd-1 <https://github.com/parchd-1>`_,\n`dojasoncom <https://github.com/dojasoncom>`_,\n`RandomStrangerOnTheInternet <https://github.com/RandomStrangerOnTheInternet>`_,\n`jonnyarnold <https://github.com/jonnyarnold>`_,\n`Mitrich3000 <https://github.com/Mitrich3000>`_,\n`audemed44 <https://github.com/audemed44>`_,\n`mkalioby <https://github.com/mkalioby>`_,\n`atlas0fd00m <https://github.com/atlas0fd00m>`_,\n`unqx <https://github.com/unqx>`_,\n`daitangio <https://github.com/daitangio>`_,\n`upils <https://github.com/upils>`_,\n`Foosec <https://github.com/Foosec>`_,\n`frispete <https://github.com/frispete>`_,\n`PH89 <https://github.com/PH89>`_,\n`amarkham09 <https://github.com/amarkham09>`_,\n`nixCodeX <https://github.com/nixCodeX>`_,\n`backelj <https://github.com/backelj>`_,\n`ohayak <https://github.com/ohayak>`_,\n`mwherman95926 <https://github.com/mwherman95926>`_,\n`andyfensham <https://github.com/andyfensham>`_,\n`mike-code <https://github.com/mike-code>`_,\n`aknrdureegaesr <https://github.com/aknrdureegaesr>`_,\n`ktulinger <https://github.com/ktulinger>`_,\n`SamGenTLEManKaka <https://github.com/SamGenTLEManKaka>`_,\n`devkral <https://github.com/devkral>`_,\n`tnusraddinov <https://github.com/tnusraddinov>`_,\n`thepeshka <https://github.com/thepeshka>`_,\n`shofstet <https://github.com/shofstet>`_,\n`the7erm <https://github.com/the7erm>`_,\n`c0da <https://github.com/c0da>`_,\n`dev4max <https://github.com/dev4max>`_,\n`ascheucher <https://github.com/ascheucher>`_,\n`Borutia <https://github.com/Borutia>`_,\n`nathan30 <https://github.com/nathan30>`_,\n`daniel55411 <https://github.com/daniel55411>`_,\n`rcarmo <https://github.com/rcarmo>`_,\n`bhernacki <https://github.com/bhernacki>`_,\n`ilep <https://github.com/ilep>`_,\n`ThKue <https://github.com/ThKue>`_,\n`repodiac <https://github.com/repodiac>`_,\n`tiuub <https://github.com/tiuub>`_,\n`Yannik <https://github.com/Yannik>`_,\n`pete312 <https://github.com/pete312>`_,\n`edkedk99 <https://github.com/edkedk99>`_,\n`UlisseMini <https://github.com/UlisseMini>`_,\n`Nicarex <https://github.com/Nicarex>`_,\n`RanjithNair1980 <https://github.com/RanjithNair1980>`_,\n`NickC-NZ <https://github.com/NickC-NZ>`_,\n`mweinelt <https://github.com/mweinelt>`_,\n`lucbouge <https://github.com/lucbouge>`_,\n`JacquelinCharbonnel <https://github.com/JacquelinCharbonnel>`_,\n`stumpylog <https://github.com/stumpylog>`_,\n`dimitrisstr <https://github.com/dimitrisstr>`_,\n`abionics <https://github.com/abionics>`_,\n`link2xt <https://github.com/link2xt>`_,\n`Docpart <https://github.com/Docpart>`_,\n`meetttttt <https://github.com/meetttttt>`_,\n`sapristi <https://github.com/sapristi>`_,\n`thomwiggers <https://github.com/thomwiggers>`_,\n`histogal <https://github.com/histogal>`_,\n`K900 <https://github.com/K900>`_,\n`homoLudenus <https://github.com/homoLudenus>`_,\n`sphh <https://github.com/sphh>`_\n\nHelp the project\n----------------\n1. Found a bug or figure out how to improve the library - open issue or merge request \ud83c\udfaf\n2. Do not know how to improve library - try to help other open projects that you use \u270b\n3. Nowhere to put your money - spend it on your family, friends, loved ones, or people around you \ud83d\udcb0\n4. Star the project \u2b50\n\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Work with email by IMAP",
"version": "1.8.0",
"project_urls": {
"Homepage": "https://github.com/ikvk/imap_tools"
},
"split_keywords": [
"imap",
" imap-client",
" python3",
" python",
" email"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "81010826fba2d1885936a9179986783892d8b2c04a9215a191d290214c1ea851",
"md5": "4b8540066c068ae84f96d9c0d4708234",
"sha256": "ac6a7a9c2a6a83cfbd09f97bd4e33c2e5adbb98882a1374ce14f03be613ed93c"
},
"downloads": -1,
"filename": "imap_tools-1.8.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "4b8540066c068ae84f96d9c0d4708234",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 33900,
"upload_time": "2024-12-11T12:30:29",
"upload_time_iso_8601": "2024-12-11T12:30:29.947771Z",
"url": "https://files.pythonhosted.org/packages/81/01/0826fba2d1885936a9179986783892d8b2c04a9215a191d290214c1ea851/imap_tools-1.8.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0bbdf7451edf9d9c26969fd43618b3ae7042b51b8ba545a13227a237f7b3ab47",
"md5": "0cd6b5f96d117d5c17085147cff56b34",
"sha256": "eda242c224ac335b46bdd571b40d5ea2539059cc1b11fd6b8ba134cfbe8f1d7f"
},
"downloads": -1,
"filename": "imap-tools-1.8.0.tar.gz",
"has_sig": false,
"md5_digest": "0cd6b5f96d117d5c17085147cff56b34",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 36220,
"upload_time": "2024-12-11T12:30:39",
"upload_time_iso_8601": "2024-12-11T12:30:39.720672Z",
"url": "https://files.pythonhosted.org/packages/0b/bd/f7451edf9d9c26969fd43618b3ae7042b51b8ba545a13227a237f7b3ab47/imap-tools-1.8.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-11 12:30:39",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ikvk",
"github_project": "imap_tools",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"tox": true,
"lcname": "imap-tools"
}