myl 0.8.12__py3-none-any.whl → 0.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {myl-0.8.12.dist-info → myl-0.9.0.dist-info}/METADATA +2 -2
- myl-0.9.0.dist-info/RECORD +7 -0
- myl.py +333 -157
- myl-0.8.12.dist-info/RECORD +0 -7
- {myl-0.8.12.dist-info → myl-0.9.0.dist-info}/LICENSE +0 -0
- {myl-0.8.12.dist-info → myl-0.9.0.dist-info}/WHEEL +0 -0
- {myl-0.8.12.dist-info → myl-0.9.0.dist-info}/entry_points.txt +0 -0
- {myl-0.8.12.dist-info → myl-0.9.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: myl
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.9.0
|
4
4
|
Summary: Dead simple IMAP CLI client
|
5
5
|
Author-email: Philipp Schmitt <philipp@schmitt.co>
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
@@ -688,7 +688,7 @@ Requires-Python: >=3.8
|
|
688
688
|
Description-Content-Type: text/markdown
|
689
689
|
License-File: LICENSE
|
690
690
|
Requires-Dist: imap-tools <2.0.0,>=1.5.0
|
691
|
-
Requires-Dist: myl-discovery >=0.6.
|
691
|
+
Requires-Dist: myl-discovery >=0.6.1
|
692
692
|
Requires-Dist: rich <14.0.0,>=13.0.0
|
693
693
|
Requires-Dist: html2text >=2024.2.26
|
694
694
|
|
@@ -0,0 +1,7 @@
|
|
1
|
+
myl.py,sha256=EthLDnMEB9lqE0T0em1DaUE9oOPHMm43Ng2AyBTCDTc,13680
|
2
|
+
myl-0.9.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
3
|
+
myl-0.9.0.dist-info/METADATA,sha256=ghRv6c27QA4-RCYNTqeG5Yrg3-0rSVltMQBmPbJuadY,43317
|
4
|
+
myl-0.9.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
5
|
+
myl-0.9.0.dist-info/entry_points.txt,sha256=q6nr0Kzim7JzreXQE3BTU4asLh2sx5-D0w1yLBOcHxc,33
|
6
|
+
myl-0.9.0.dist-info/top_level.txt,sha256=Wn88OJVVWyYSsKVoqzlHXxfFxh5IbrJ_Yw-ldNLe7Po,4
|
7
|
+
myl-0.9.0.dist-info/RECORD,,
|
myl.py
CHANGED
@@ -2,13 +2,20 @@
|
|
2
2
|
# coding: utf-8
|
3
3
|
|
4
4
|
import argparse
|
5
|
-
import html2text
|
6
|
-
import json
|
7
5
|
import logging
|
8
6
|
import ssl
|
9
7
|
import sys
|
8
|
+
from json import dumps as json_dumps
|
10
9
|
|
11
|
-
import
|
10
|
+
import html2text
|
11
|
+
from imap_tools.consts import MailMessageFlags
|
12
|
+
from imap_tools.mailbox import (
|
13
|
+
BaseMailBox,
|
14
|
+
MailBox,
|
15
|
+
MailBoxTls,
|
16
|
+
MailBoxUnencrypted,
|
17
|
+
)
|
18
|
+
from imap_tools.query import AND
|
12
19
|
from myldiscovery import autodiscover
|
13
20
|
from rich import print, print_json
|
14
21
|
from rich.console import Console
|
@@ -23,13 +30,88 @@ GMAIL_SENT_FOLDER = "[Gmail]/Sent Mail"
|
|
23
30
|
# GMAIL_ALL_FOLDER = "[Gmail]/All Mail"
|
24
31
|
|
25
32
|
|
33
|
+
class MissingServerException(Exception):
|
34
|
+
pass
|
35
|
+
|
36
|
+
|
26
37
|
def error_msg(msg):
|
27
38
|
print(f"[red]{msg}[/red]", file=sys.stderr)
|
28
39
|
|
29
40
|
|
41
|
+
def mail_to_dict(msg, date_format="%Y-%m-%d %H:%M:%S"):
|
42
|
+
return {
|
43
|
+
"uid": msg.uid,
|
44
|
+
"subject": msg.subject,
|
45
|
+
"from": msg.from_,
|
46
|
+
"to": msg.to,
|
47
|
+
"date": msg.date.strftime(date_format),
|
48
|
+
"timestamp": str(int(msg.date.timestamp())),
|
49
|
+
"unread": mail_is_unread(msg),
|
50
|
+
"flags": msg.flags,
|
51
|
+
"content": {
|
52
|
+
"raw": msg.obj.as_string(),
|
53
|
+
"html": msg.html,
|
54
|
+
"text": msg.text,
|
55
|
+
},
|
56
|
+
"attachments": msg.attachments,
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
def mail_to_json(msg, date_format="%Y-%m-%d %H:%M:%S"):
|
61
|
+
return json_dumps(mail_to_dict(msg, date_format))
|
62
|
+
|
63
|
+
|
64
|
+
def mail_is_unread(msg):
|
65
|
+
return MailMessageFlags.SEEN not in msg.flags
|
66
|
+
|
67
|
+
|
30
68
|
def parse_args():
|
31
69
|
parser = argparse.ArgumentParser()
|
32
|
-
parser.
|
70
|
+
subparsers = parser.add_subparsers(
|
71
|
+
dest="command", help="Available commands"
|
72
|
+
)
|
73
|
+
|
74
|
+
# Default command: list all emails
|
75
|
+
subparsers.add_parser("list", help="List all emails")
|
76
|
+
|
77
|
+
# Get/show email command
|
78
|
+
get_parser = subparsers.add_parser(
|
79
|
+
"get", help="Retrieve a specific email or attachment"
|
80
|
+
)
|
81
|
+
get_parser.add_argument("MAILID", help="Mail ID to fetch", type=int)
|
82
|
+
get_parser.add_argument(
|
83
|
+
"ATTACHMENT",
|
84
|
+
help="Name of the attachment to fetch",
|
85
|
+
nargs="?",
|
86
|
+
default=None,
|
87
|
+
)
|
88
|
+
|
89
|
+
# Delete email command
|
90
|
+
delete_parser = subparsers.add_parser("delete", help="Delete an email")
|
91
|
+
delete_parser.add_argument(
|
92
|
+
"MAILIDS", help="Mail ID(s) to delete", type=int, nargs="+"
|
93
|
+
)
|
94
|
+
|
95
|
+
# Mark email as read/unread
|
96
|
+
mark_read_parser = subparsers.add_parser(
|
97
|
+
"read", help="mark an email as read"
|
98
|
+
)
|
99
|
+
mark_read_parser.add_argument(
|
100
|
+
"MAILIDS", help="Mail ID(s) to mark as read", type=int, nargs="+"
|
101
|
+
)
|
102
|
+
mark_unread_parser = subparsers.add_parser(
|
103
|
+
"unread", help="mark an email as unread"
|
104
|
+
)
|
105
|
+
mark_unread_parser.add_argument(
|
106
|
+
"MAILIDS", help="Mail ID(s) to mark as unread", type=int, nargs="+"
|
107
|
+
)
|
108
|
+
|
109
|
+
# Optional arguments
|
110
|
+
parser.add_argument(
|
111
|
+
"-d", "--debug", help="Enable debug mode", action="store_true"
|
112
|
+
)
|
113
|
+
|
114
|
+
# IMAP connection settings
|
33
115
|
parser.add_argument(
|
34
116
|
"-s", "--server", help="IMAP server address", required=False
|
35
117
|
)
|
@@ -45,7 +127,7 @@ def parse_args():
|
|
45
127
|
"--auto",
|
46
128
|
help="Autodiscovery of the required server and port",
|
47
129
|
action="store_true",
|
48
|
-
default=
|
130
|
+
default=True,
|
49
131
|
)
|
50
132
|
parser.add_argument(
|
51
133
|
"-P", "--port", help="IMAP server port", default=IMAP_PORT
|
@@ -60,16 +142,8 @@ def parse_args():
|
|
60
142
|
action="store_true",
|
61
143
|
default=False,
|
62
144
|
)
|
63
|
-
|
64
|
-
|
65
|
-
"--count",
|
66
|
-
help="Number of messages to fetch",
|
67
|
-
default=10,
|
68
|
-
type=int,
|
69
|
-
)
|
70
|
-
parser.add_argument(
|
71
|
-
"-m", "--mark-seen", help="Mark seen", action="store_true"
|
72
|
-
)
|
145
|
+
|
146
|
+
# Credentials
|
73
147
|
parser.add_argument(
|
74
148
|
"-u", "--username", help="IMAP username", required=True
|
75
149
|
)
|
@@ -80,9 +154,32 @@ def parse_args():
|
|
80
154
|
help="IMAP password (file path)",
|
81
155
|
type=argparse.FileType("r"),
|
82
156
|
)
|
157
|
+
|
158
|
+
# Display preferences
|
159
|
+
parser.add_argument(
|
160
|
+
"-c",
|
161
|
+
"--count",
|
162
|
+
help="Number of messages to fetch",
|
163
|
+
default=10,
|
164
|
+
type=int,
|
165
|
+
)
|
83
166
|
parser.add_argument(
|
84
167
|
"-t", "--no-title", help="Do not show title", action="store_true"
|
85
168
|
)
|
169
|
+
parser.add_argument(
|
170
|
+
"--date-format", help="Date format", default="%H:%M %d/%m/%Y"
|
171
|
+
)
|
172
|
+
|
173
|
+
# IMAP actions
|
174
|
+
parser.add_argument(
|
175
|
+
"-m",
|
176
|
+
"--mark-seen",
|
177
|
+
help="Mark seen",
|
178
|
+
action="store_true",
|
179
|
+
default=False,
|
180
|
+
)
|
181
|
+
|
182
|
+
# Email filtering
|
86
183
|
parser.add_argument("-f", "--folder", help="IMAP folder", default="INBOX")
|
87
184
|
parser.add_argument(
|
88
185
|
"--sent",
|
@@ -90,7 +187,21 @@ def parse_args():
|
|
90
187
|
action="store_true",
|
91
188
|
)
|
92
189
|
parser.add_argument("-S", "--search", help="Search string", default="ALL")
|
93
|
-
parser.add_argument(
|
190
|
+
parser.add_argument(
|
191
|
+
"--unread",
|
192
|
+
help="Limit to unread emails",
|
193
|
+
action="store_true",
|
194
|
+
default=False,
|
195
|
+
)
|
196
|
+
|
197
|
+
# Output preferences
|
198
|
+
parser.add_argument(
|
199
|
+
"-H",
|
200
|
+
"--html",
|
201
|
+
help="Show HTML email",
|
202
|
+
action="store_true",
|
203
|
+
default=False,
|
204
|
+
)
|
94
205
|
parser.add_argument(
|
95
206
|
"-j",
|
96
207
|
"--json",
|
@@ -105,24 +216,11 @@ def parse_args():
|
|
105
216
|
action="store_true",
|
106
217
|
default=False,
|
107
218
|
)
|
108
|
-
parser.add_argument("MAILID", help="Mail ID to fetch", nargs="?")
|
109
|
-
parser.add_argument(
|
110
|
-
"ATTACHMENT", help="Name of the attachment to fetch", nargs="?"
|
111
|
-
)
|
112
219
|
|
113
220
|
return parser.parse_args()
|
114
221
|
|
115
222
|
|
116
|
-
def
|
117
|
-
console = Console()
|
118
|
-
args = parse_args()
|
119
|
-
logging.basicConfig(
|
120
|
-
format="%(message)s",
|
121
|
-
handlers=[RichHandler(console=console)],
|
122
|
-
level=logging.DEBUG if args.debug else logging.INFO,
|
123
|
-
)
|
124
|
-
LOGGER.debug(args)
|
125
|
-
|
223
|
+
def mb_connect(console, args) -> BaseMailBox:
|
126
224
|
imap_password = args.password or (
|
127
225
|
args.password_file and args.password_file.read()
|
128
226
|
)
|
@@ -140,13 +238,16 @@ def main():
|
|
140
238
|
if args.auto:
|
141
239
|
try:
|
142
240
|
settings = autodiscover(
|
143
|
-
args.username,
|
144
|
-
|
241
|
+
args.username,
|
242
|
+
password=imap_password,
|
243
|
+
insecure=args.insecure,
|
244
|
+
).get("imap", {})
|
145
245
|
except Exception:
|
146
246
|
error_msg("Failed to autodiscover IMAP settings")
|
147
247
|
if args.debug:
|
148
248
|
console.print_exception(show_locals=True)
|
149
|
-
|
249
|
+
raise
|
250
|
+
|
150
251
|
LOGGER.debug(f"Discovered settings: {settings})")
|
151
252
|
args.server = settings.get("server")
|
152
253
|
args.port = settings.get("port", IMAP_PORT)
|
@@ -164,11 +265,87 @@ def main():
|
|
164
265
|
"- set --google if you are using a Gmail account\n"
|
165
266
|
"- use --auto to attempt autodiscovery"
|
166
267
|
)
|
167
|
-
|
268
|
+
raise MissingServerException()
|
269
|
+
|
270
|
+
ssl_context = ssl.create_default_context()
|
271
|
+
if args.insecure:
|
272
|
+
ssl_context.check_hostname = False
|
273
|
+
ssl_context.verify_mode = ssl.CERT_NONE
|
274
|
+
|
275
|
+
mb_kwargs = {"host": args.server, "port": args.port}
|
276
|
+
if args.ssl:
|
277
|
+
mb = MailBox
|
278
|
+
mb_kwargs["ssl_context"] = ssl_context
|
279
|
+
elif args.starttls:
|
280
|
+
mb = MailBoxTls
|
281
|
+
mb_kwargs["ssl_context"] = ssl_context
|
282
|
+
else:
|
283
|
+
mb = MailBoxUnencrypted
|
284
|
+
|
285
|
+
mailbox = mb(**mb_kwargs)
|
286
|
+
mailbox.login(args.username, imap_password, args.folder)
|
287
|
+
return mailbox
|
288
|
+
|
289
|
+
|
290
|
+
def display_single_mail(
|
291
|
+
mailbox: BaseMailBox,
|
292
|
+
mail_id: int,
|
293
|
+
attachment: str | None = None,
|
294
|
+
mark_seen: bool = False,
|
295
|
+
raw: bool = False,
|
296
|
+
html: bool = False,
|
297
|
+
json: bool = False,
|
298
|
+
):
|
299
|
+
LOGGER.debug("Fetch mail %s", mail_id)
|
300
|
+
msg = next(mailbox.fetch(f"UID {mail_id}", mark_seen=mark_seen))
|
301
|
+
LOGGER.debug("Fetched mail %s", msg)
|
302
|
+
|
303
|
+
if attachment:
|
304
|
+
for att in msg.attachments:
|
305
|
+
if att.filename == attachment:
|
306
|
+
sys.stdout.buffer.write(att.payload)
|
307
|
+
return 0
|
308
|
+
print(
|
309
|
+
f"attachment {attachment} not found",
|
310
|
+
file=sys.stderr,
|
311
|
+
)
|
312
|
+
return 1
|
313
|
+
|
314
|
+
if html:
|
315
|
+
output = msg.text
|
316
|
+
if raw:
|
317
|
+
output = msg.html
|
318
|
+
else:
|
319
|
+
output = html2text.html2text(msg.html)
|
320
|
+
print(output)
|
321
|
+
elif raw:
|
322
|
+
print(msg.obj.as_string())
|
323
|
+
return 0
|
324
|
+
elif json:
|
325
|
+
print_json(mail_to_json(msg))
|
326
|
+
return 0
|
327
|
+
else:
|
328
|
+
print(msg.text)
|
168
329
|
|
330
|
+
for att in msg.attachments:
|
331
|
+
print(f"📎 Attachment: {att.filename}", file=sys.stderr)
|
332
|
+
return 0
|
333
|
+
|
334
|
+
|
335
|
+
def display_emails(
|
336
|
+
mailbox,
|
337
|
+
console,
|
338
|
+
no_title=False,
|
339
|
+
search="ALL",
|
340
|
+
unread_only=False,
|
341
|
+
count=10,
|
342
|
+
mark_seen=False,
|
343
|
+
json=False,
|
344
|
+
date_format="%H:%M %d/%m/%Y",
|
345
|
+
):
|
169
346
|
json_data = []
|
170
347
|
table = Table(
|
171
|
-
show_header=not
|
348
|
+
show_header=not no_title,
|
172
349
|
header_style="bold",
|
173
350
|
expand=True,
|
174
351
|
show_lines=False,
|
@@ -182,135 +359,134 @@ def main():
|
|
182
359
|
table.add_column("From", style="blue", no_wrap=True, ratio=2)
|
183
360
|
table.add_column("Date", style="cyan", no_wrap=True)
|
184
361
|
|
185
|
-
|
186
|
-
|
187
|
-
ssl_context.check_hostname = False
|
188
|
-
ssl_context.verify_mode = ssl.CERT_NONE
|
362
|
+
if unread_only:
|
363
|
+
search = AND(seen=False)
|
189
364
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
365
|
+
for msg in mailbox.fetch(
|
366
|
+
criteria=search,
|
367
|
+
reverse=True,
|
368
|
+
bulk=True,
|
369
|
+
limit=count,
|
370
|
+
mark_seen=mark_seen,
|
371
|
+
headers_only=False, # required for attachments
|
372
|
+
):
|
373
|
+
subj_prefix = "🆕 " if mail_is_unread(msg) else ""
|
374
|
+
subj_prefix += "📎 " if len(msg.attachments) > 0 else ""
|
375
|
+
subject = (
|
376
|
+
msg.subject.replace("\n", "") if msg.subject else "<no-subject>"
|
377
|
+
)
|
378
|
+
if json:
|
379
|
+
json_data.append(mail_to_dict(msg))
|
380
|
+
else:
|
381
|
+
table.add_row(
|
382
|
+
msg.uid if msg.uid else "???",
|
383
|
+
f"{subj_prefix}{subject}",
|
384
|
+
msg.from_,
|
385
|
+
(msg.date.strftime(date_format) if msg.date else "???"),
|
386
|
+
)
|
387
|
+
if table.row_count >= count:
|
388
|
+
break
|
389
|
+
|
390
|
+
if json:
|
391
|
+
print_json(json_dumps(json_data))
|
197
392
|
else:
|
198
|
-
|
393
|
+
console.print(table)
|
394
|
+
if table.row_count == 0:
|
395
|
+
print(
|
396
|
+
"[yellow italic]No messages[/yellow italic]",
|
397
|
+
file=sys.stderr,
|
398
|
+
)
|
399
|
+
return 0
|
400
|
+
|
401
|
+
|
402
|
+
def delete_emails(mailbox: BaseMailBox, mail_ids: list):
|
403
|
+
LOGGER.warning("Deleting mails %s", mail_ids)
|
404
|
+
mailbox.delete([str(x) for x in mail_ids])
|
405
|
+
return 0
|
406
|
+
|
407
|
+
|
408
|
+
def set_seen(mailbox: BaseMailBox, mail_ids: list, value=True):
|
409
|
+
LOGGER.info(
|
410
|
+
"Marking mails as %s: %s", "read" if value else "unread", mail_ids
|
411
|
+
)
|
412
|
+
mailbox.flag(
|
413
|
+
[str(x) for x in mail_ids],
|
414
|
+
flag_set=(MailMessageFlags.SEEN),
|
415
|
+
value=value,
|
416
|
+
)
|
417
|
+
return 0
|
418
|
+
|
419
|
+
|
420
|
+
def mark_read(mailbox: BaseMailBox, mail_ids: list):
|
421
|
+
return set_seen(mailbox, mail_ids, value=True)
|
422
|
+
|
423
|
+
|
424
|
+
def mark_unread(mailbox: BaseMailBox, mail_ids: list):
|
425
|
+
return set_seen(mailbox, mail_ids, value=False)
|
426
|
+
|
427
|
+
|
428
|
+
def main() -> int:
|
429
|
+
console = Console()
|
430
|
+
args = parse_args()
|
431
|
+
logging.basicConfig(
|
432
|
+
format="%(message)s",
|
433
|
+
handlers=[RichHandler(console=console)],
|
434
|
+
level=logging.DEBUG if args.debug else logging.INFO,
|
435
|
+
)
|
436
|
+
LOGGER.debug(args)
|
199
437
|
|
200
438
|
try:
|
201
|
-
with
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
439
|
+
with mb_connect(console, args) as mailbox:
|
440
|
+
# inbox display
|
441
|
+
if args.command in ["list", None]:
|
442
|
+
return display_emails(
|
443
|
+
mailbox=mailbox,
|
444
|
+
console=console,
|
445
|
+
no_title=args.no_title,
|
446
|
+
search=args.search,
|
447
|
+
unread_only=args.unread,
|
448
|
+
count=args.count,
|
449
|
+
mark_seen=args.mark_seen,
|
450
|
+
json=args.json,
|
451
|
+
date_format=args.date_format,
|
209
452
|
)
|
210
|
-
if args.ATTACHMENT:
|
211
|
-
for att in msg.attachments:
|
212
|
-
if att.filename == args.ATTACHMENT:
|
213
|
-
sys.stdout.buffer.write(att.payload)
|
214
|
-
return 0
|
215
|
-
print(
|
216
|
-
f"Attachment {args.ATTACHMENT} not found",
|
217
|
-
file=sys.stderr,
|
218
|
-
)
|
219
|
-
return 1
|
220
|
-
else:
|
221
|
-
if args.raw:
|
222
|
-
print(msg.obj.as_string())
|
223
|
-
return 0
|
224
|
-
elif args.json:
|
225
|
-
print_json(
|
226
|
-
json.dumps(
|
227
|
-
{
|
228
|
-
"uid": msg.uid,
|
229
|
-
"subject": msg.subject,
|
230
|
-
"from": msg.from_,
|
231
|
-
"to": msg.to,
|
232
|
-
"date": msg.date.strftime(
|
233
|
-
"%Y-%m-%d %H:%M:%S"
|
234
|
-
),
|
235
|
-
"timestamp": str(
|
236
|
-
int(msg.date.timestamp())
|
237
|
-
),
|
238
|
-
"content": {
|
239
|
-
"raw": msg.obj.as_string(),
|
240
|
-
"html": msg.html,
|
241
|
-
"text": msg.text,
|
242
|
-
},
|
243
|
-
"attachments": msg.attachments,
|
244
|
-
}
|
245
|
-
)
|
246
|
-
)
|
247
|
-
return 0
|
248
|
-
|
249
|
-
output = msg.text
|
250
|
-
if args.html:
|
251
|
-
if args.raw:
|
252
|
-
output = msg.html
|
253
|
-
else:
|
254
|
-
output = html2text.html2text(msg.html)
|
255
|
-
print(output)
|
256
|
-
for att in msg.attachments:
|
257
|
-
print(
|
258
|
-
f"📎 Attachment: {att.filename}", file=sys.stderr
|
259
|
-
)
|
260
|
-
return 0
|
261
453
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
if msg.subject
|
274
|
-
else "<no-subject>"
|
454
|
+
# single email
|
455
|
+
# FIXME $ myl 219 raises an argparse error
|
456
|
+
elif args.command in ["get", "show", "display"]:
|
457
|
+
return display_single_mail(
|
458
|
+
mailbox=mailbox,
|
459
|
+
mail_id=args.MAILID,
|
460
|
+
attachment=args.ATTACHMENT,
|
461
|
+
mark_seen=args.mark_seen,
|
462
|
+
raw=args.raw,
|
463
|
+
html=args.html,
|
464
|
+
json=args.json,
|
275
465
|
)
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
if msg.date
|
301
|
-
else "???"
|
302
|
-
),
|
303
|
-
)
|
304
|
-
if table.row_count >= args.count:
|
305
|
-
break
|
306
|
-
|
307
|
-
if args.json:
|
308
|
-
print_json(json.dumps(json_data))
|
309
|
-
else:
|
310
|
-
console.print(table)
|
311
|
-
if table.row_count == 0:
|
312
|
-
print("[yellow italic]No messages[/yellow italic]", file=sys.stderr)
|
313
|
-
return 0
|
466
|
+
|
467
|
+
# mark emails as read
|
468
|
+
elif args.command in ["read"]:
|
469
|
+
return mark_read(
|
470
|
+
mailbox=mailbox,
|
471
|
+
mail_ids=args.MAILIDS,
|
472
|
+
)
|
473
|
+
|
474
|
+
elif args.command in ["unread"]:
|
475
|
+
return mark_unread(
|
476
|
+
mailbox=mailbox,
|
477
|
+
mail_ids=args.MAILIDS,
|
478
|
+
)
|
479
|
+
|
480
|
+
# delete email
|
481
|
+
elif args.command in ["delete", "remove"]:
|
482
|
+
return delete_emails(
|
483
|
+
mailbox=mailbox,
|
484
|
+
mail_ids=args.MAILIDS,
|
485
|
+
)
|
486
|
+
else:
|
487
|
+
error_msg(f"Unknown command: {args.command}")
|
488
|
+
return 1
|
489
|
+
|
314
490
|
except Exception:
|
315
491
|
console.print_exception(show_locals=True)
|
316
492
|
return 1
|
myl-0.8.12.dist-info/RECORD
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
myl.py,sha256=l3hgASE9E3Po7C5pB-yxaFjteMh15GKHwsnW693Z-pc,10591
|
2
|
-
myl-0.8.12.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
3
|
-
myl-0.8.12.dist-info/METADATA,sha256=LkmLWD0Q6gwkDDbDRveC8UFtn4xLCe2EzORSffywUB4,43318
|
4
|
-
myl-0.8.12.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
5
|
-
myl-0.8.12.dist-info/entry_points.txt,sha256=q6nr0Kzim7JzreXQE3BTU4asLh2sx5-D0w1yLBOcHxc,33
|
6
|
-
myl-0.8.12.dist-info/top_level.txt,sha256=Wn88OJVVWyYSsKVoqzlHXxfFxh5IbrJ_Yw-ldNLe7Po,4
|
7
|
-
myl-0.8.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|