|
76 | 76 | DRAFT = br'\Draft'
|
77 | 77 | RECENT = br'\Recent' # This flag is read-only
|
78 | 78 |
|
| 79 | +# Special folders, see RFC6154 |
| 80 | +# \Flagged is omitted because it is the same as the flag defined above |
| 81 | +ALL = br'\All' |
| 82 | +ARCHIVE = br'\Archive' |
| 83 | +DRAFTS = br'\Drafts' |
| 84 | +JUNK = br'\Junk' |
| 85 | +SENT = br'\Sent' |
| 86 | +TRASH = br'\Trash' |
| 87 | + |
| 88 | +# Personal namespaces that are common among providers |
| 89 | +# used as a fallback when the server does not support the NAMESPACE capability |
| 90 | +_POPULAR_PERSONAL_NAMESPACES = (("", ""), ("INBOX.", ".")) |
| 91 | + |
| 92 | +# Names of special folders that are common among providers |
| 93 | +_POPULAR_SPECIAL_FOLDERS = { |
| 94 | + SENT: ("Sent", "Sent Items", "Sent items"), |
| 95 | + DRAFTS: ("Drafts",), |
| 96 | + ARCHIVE: ("Archive",), |
| 97 | + TRASH: ("Trash", "Deleted Items", "Deleted Messages"), |
| 98 | + JUNK: ("Junk", "Spam") |
| 99 | +} |
79 | 100 |
|
80 | 101 | class Namespace(tuple):
|
81 | 102 |
|
@@ -565,6 +586,42 @@ def _proc_folder_list(self, folder_data):
|
565 | 586 | ret.append((flags, delim, name))
|
566 | 587 | return ret
|
567 | 588 |
|
| 589 | + def find_special_folder(self, folder_flag): |
| 590 | + """Try to locate a special folder, like the Sent or Trash folder. |
| 591 | +
|
| 592 | + >>> server.find_special_folder(imapclient.SENT) |
| 593 | + 'INBOX.Sent' |
| 594 | +
|
| 595 | + This function tries its best to find the correct folder (if any) but |
| 596 | + uses heuristics when the server is unable to precisely tell where |
| 597 | + special folders are located. |
| 598 | +
|
| 599 | + Returns the name of the folder if found, or None otherwise. |
| 600 | + """ |
| 601 | + # Detect folder by looking for known attributes |
| 602 | + # TODO: avoid listing all folders by using extended LIST (RFC6154) |
| 603 | + if self.has_capability('SPECIAL-USE'): |
| 604 | + for folder in self.list_folders(): |
| 605 | + if folder and len(folder[0]) > 1 and folder[0][1] == folder_flag: |
| 606 | + return folder[2] |
| 607 | + |
| 608 | + # Detect folder by looking for common names |
| 609 | + # We only look for folders in the "personal" namespace of the user |
| 610 | + if self.has_capability('NAMESPACE'): |
| 611 | + personal_namespaces = self.namespace().personal |
| 612 | + else: |
| 613 | + personal_namespaces = _POPULAR_PERSONAL_NAMESPACES |
| 614 | + |
| 615 | + for personal_namespace in personal_namespaces: |
| 616 | + for pattern in _POPULAR_SPECIAL_FOLDERS.get(folder_flag, tuple()): |
| 617 | + pattern = personal_namespace[0] + pattern |
| 618 | + sent_folders = self.list_folders(pattern=pattern) |
| 619 | + if sent_folders: |
| 620 | + return sent_folders[0][2] |
| 621 | + |
| 622 | + return None |
| 623 | + |
| 624 | + |
568 | 625 | def select_folder(self, folder, readonly=False):
|
569 | 626 | """Set the current folder on the server.
|
570 | 627 |
|
|
0 commit comments