sygmail 0.1.0__py3-none-any.whl → 0.1.1__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.
- sygmail/cli.py +6 -0
- sygmail/client.py +30 -2
- {sygmail-0.1.0.dist-info → sygmail-0.1.1.dist-info}/METADATA +36 -7
- sygmail-0.1.1.dist-info/RECORD +10 -0
- sygmail-0.1.0.dist-info/RECORD +0 -10
- {sygmail-0.1.0.dist-info → sygmail-0.1.1.dist-info}/WHEEL +0 -0
- {sygmail-0.1.0.dist-info → sygmail-0.1.1.dist-info}/entry_points.txt +0 -0
- {sygmail-0.1.0.dist-info → sygmail-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {sygmail-0.1.0.dist-info → sygmail-0.1.1.dist-info}/top_level.txt +0 -0
sygmail/cli.py
CHANGED
|
@@ -36,6 +36,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
36
36
|
config_set_parser.add_argument("--env", default=".env", help="Path to .env file")
|
|
37
37
|
config_set_parser.add_argument("--from", dest="from_addr", help="From address")
|
|
38
38
|
config_set_parser.add_argument("--app-password", help="Gmail app password")
|
|
39
|
+
config_set_parser.add_argument(
|
|
40
|
+
"--use-keyring",
|
|
41
|
+
action="store_true",
|
|
42
|
+
help="Store app password in keyring instead of .env",
|
|
43
|
+
)
|
|
39
44
|
config_set_parser.add_argument("--to", help="To address")
|
|
40
45
|
config_set_parser.add_argument("--subject", help="Email subject")
|
|
41
46
|
config_set_parser.add_argument("--contents", help="Email contents")
|
|
@@ -110,6 +115,7 @@ def run_config_set(args: argparse.Namespace) -> int:
|
|
|
110
115
|
subject=args.subject,
|
|
111
116
|
contents=args.contents,
|
|
112
117
|
attachments_path=args.attachments_path,
|
|
118
|
+
use_keyring=args.use_keyring,
|
|
113
119
|
persist=True,
|
|
114
120
|
)
|
|
115
121
|
return 0
|
sygmail/client.py
CHANGED
|
@@ -7,8 +7,14 @@ from typing import Iterable, List, Optional
|
|
|
7
7
|
|
|
8
8
|
import yagmail
|
|
9
9
|
|
|
10
|
+
try:
|
|
11
|
+
import keyring
|
|
12
|
+
except ImportError: # pragma: no cover - optional dependency
|
|
13
|
+
keyring = None
|
|
14
|
+
|
|
10
15
|
DEFAULT_SUBJECT = "Process Completed"
|
|
11
16
|
DEFAULT_CONTENTS_TEMPLATE = "{script_name} has finished running."
|
|
17
|
+
KEYRING_SERVICE = "sygmail"
|
|
12
18
|
|
|
13
19
|
ENV_KEYS = {
|
|
14
20
|
"from_addr": "SYGMAIL_FROM",
|
|
@@ -80,13 +86,20 @@ class Sygmail:
|
|
|
80
86
|
subject: Optional[str] = None,
|
|
81
87
|
contents: Optional[str] = None,
|
|
82
88
|
attachments_path: Optional[str] = None,
|
|
89
|
+
use_keyring: bool = False,
|
|
83
90
|
persist: bool = True,
|
|
84
91
|
) -> None:
|
|
85
92
|
if from_addr is None and from_ is not None:
|
|
86
93
|
from_addr = from_
|
|
87
94
|
if from_addr is not None:
|
|
88
95
|
self.config.from_addr = from_addr
|
|
89
|
-
if app_password is not None:
|
|
96
|
+
if app_password is not None and use_keyring:
|
|
97
|
+
resolved_from = from_addr or self.config.from_addr
|
|
98
|
+
if not resolved_from:
|
|
99
|
+
raise ValueError("from_addr is required to store keyring password")
|
|
100
|
+
_store_keyring_password(resolved_from, app_password)
|
|
101
|
+
self.config.app_password = None
|
|
102
|
+
elif app_password is not None:
|
|
90
103
|
self.config.app_password = app_password
|
|
91
104
|
if to is not None:
|
|
92
105
|
self.config.to = to
|
|
@@ -117,7 +130,7 @@ class Sygmail:
|
|
|
117
130
|
**kwargs,
|
|
118
131
|
) -> None:
|
|
119
132
|
resolved_from = from_addr or from_ or self.config.from_addr
|
|
120
|
-
app_password = self.config.app_password
|
|
133
|
+
app_password = self.config.app_password or _get_keyring_password(resolved_from)
|
|
121
134
|
target = to or self.config.to or resolved_from
|
|
122
135
|
|
|
123
136
|
if not resolved_from or not app_password or not target:
|
|
@@ -205,6 +218,21 @@ def _warn_missing_attachments(paths: Iterable[str]) -> None:
|
|
|
205
218
|
warnings.warn(f"missing attachments ignored: {joined}", stacklevel=3)
|
|
206
219
|
|
|
207
220
|
|
|
221
|
+
def _get_keyring_password(username: Optional[str]) -> Optional[str]:
|
|
222
|
+
if not username or keyring is None:
|
|
223
|
+
return None
|
|
224
|
+
try:
|
|
225
|
+
return keyring.get_password(KEYRING_SERVICE, username)
|
|
226
|
+
except Exception:
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _store_keyring_password(username: str, password: str) -> None:
|
|
231
|
+
if keyring is None:
|
|
232
|
+
raise RuntimeError("keyring is not installed")
|
|
233
|
+
keyring.set_password(KEYRING_SERVICE, username, password)
|
|
234
|
+
|
|
235
|
+
|
|
208
236
|
def _read_env_file(env_path: str) -> dict:
|
|
209
237
|
path = Path(env_path)
|
|
210
238
|
if not path.exists():
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sygmail
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Lightweight Gmail notification wrapper
|
|
5
|
-
Author
|
|
5
|
+
Author: Satoshi Nakabayashi
|
|
6
6
|
Requires-Python: >=3.9
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
9
9
|
Requires-Dist: yagmail
|
|
10
|
+
Provides-Extra: keyring
|
|
11
|
+
Requires-Dist: keyring; extra == "keyring"
|
|
10
12
|
Dynamic: license-file
|
|
11
13
|
|
|
12
14
|
# sygmail
|
|
@@ -30,6 +32,7 @@ pip install sygmail
|
|
|
30
32
|
|
|
31
33
|
- Python 3.9+
|
|
32
34
|
- Dependency: `yagmail`
|
|
35
|
+
- Optional: `keyring` (for OS credential store support)
|
|
33
36
|
|
|
34
37
|
## Quick start
|
|
35
38
|
|
|
@@ -53,9 +56,31 @@ SYGMAIL_APP_PASSWORD=app-password
|
|
|
53
56
|
SYGMAIL_TO=to@example.com
|
|
54
57
|
SYGMAIL_SUBJECT=Process Completed
|
|
55
58
|
SYGMAIL_CONTENTS={script_name} has finished running.
|
|
56
|
-
SYGMAIL_ATTACHMENTS_PATH
|
|
59
|
+
SYGMAIL_ATTACHMENTS_PATH=/path/to/folder
|
|
57
60
|
```
|
|
58
61
|
|
|
62
|
+
If you use keyring, you can leave `SYGMAIL_APP_PASSWORD` empty.
|
|
63
|
+
|
|
64
|
+
Install keyring support:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
pip install "sygmail[keyring]"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Keyring usage:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
python -m sygmail config set --from you@gmail.com --app-password "app-password" --use-keyring
|
|
74
|
+
python -m sygmail send
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Notes:
|
|
78
|
+
|
|
79
|
+
- Passwords are stored under the service name `sygmail` with the `from` address as the username.
|
|
80
|
+
- If `SYGMAIL_APP_PASSWORD` is set, it is used first; otherwise keyring is used.
|
|
81
|
+
- Storage uses your OS credential manager (macOS Keychain, Windows Credential Manager, or a Linux keyring).
|
|
82
|
+
- To remove a stored password, delete it from your OS credential manager.
|
|
83
|
+
|
|
59
84
|
## Defaults
|
|
60
85
|
|
|
61
86
|
- Subject: `Process Completed`
|
|
@@ -98,8 +123,8 @@ python -m sygmail send \
|
|
|
98
123
|
--to to@example.com \
|
|
99
124
|
--subject "Process Completed" \
|
|
100
125
|
--contents "[sygmail notification]" \
|
|
101
|
-
--attachments
|
|
102
|
-
--attachments-path
|
|
126
|
+
--attachments /path/to/file \
|
|
127
|
+
--attachments-path /path/to/folder/
|
|
103
128
|
```
|
|
104
129
|
|
|
105
130
|
- If `--contents` is omitted, CLI uses `[sygmail notification]` without editing `.env`.
|
|
@@ -111,10 +136,14 @@ python -m sygmail send
|
|
|
111
136
|
|
|
112
137
|
python -m sygmail send --subject "Job Done" --contents "[sygmail notification]"
|
|
113
138
|
|
|
114
|
-
python -m sygmail send --attachments
|
|
139
|
+
python -m sygmail send --attachments /path/to/file-a.txt /path/to/file-b.txt
|
|
140
|
+
|
|
141
|
+
python -m sygmail send --attachments-path /path/to/folder/
|
|
115
142
|
|
|
116
143
|
python -m sygmail config set --from you@gmail.com --app-password "app-password"
|
|
117
144
|
|
|
145
|
+
python -m sygmail config set --from you@gmail.com --app-password "app-password" --use-keyring
|
|
146
|
+
|
|
118
147
|
python -m sygmail config show
|
|
119
148
|
```
|
|
120
149
|
|
|
@@ -128,7 +157,7 @@ python -m sygmail config set \
|
|
|
128
157
|
--to to@example.com \
|
|
129
158
|
--subject "Process Completed" \
|
|
130
159
|
--contents "{script_name} has finished running." \
|
|
131
|
-
--attachments-path
|
|
160
|
+
--attachments-path /path/to/folder/
|
|
132
161
|
|
|
133
162
|
python -m sygmail config reset --env .env
|
|
134
163
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
sygmail/__init__.py,sha256=eGoC5SwKCqe1cYhH1LuNPogYeeOTd636Wlnt70nRRB8,83
|
|
2
|
+
sygmail/__main__.py,sha256=MHKZ_ae3fSLGTLUUMOx15fWdeOnJSHhq-zslRP5F5Lc,79
|
|
3
|
+
sygmail/cli.py,sha256=IQHQOIPWokRyv9ti34FEqKKXCgxiA6DyHr-MuSy5Ozg,5161
|
|
4
|
+
sygmail/client.py,sha256=O4x4CWln4Ju3DRXdm0WTgDyPykE4nm1Jm3y8OlA-N3s,9199
|
|
5
|
+
sygmail-0.1.1.dist-info/licenses/LICENSE,sha256=Oakmmh4GWfLsNpdR0BBBCzmhIf_3rEeIjrB_hvolczk,1076
|
|
6
|
+
sygmail-0.1.1.dist-info/METADATA,sha256=_3lOx0T_IT_PZxb-K22Knw91ZBQlxHkaA07D91NENDk,4694
|
|
7
|
+
sygmail-0.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
+
sygmail-0.1.1.dist-info/entry_points.txt,sha256=_6WdaniMLQk9VEx1MnYSNXMIyt7Csce2-PG6mopUGtI,45
|
|
9
|
+
sygmail-0.1.1.dist-info/top_level.txt,sha256=umbnP2FZMQ4N-tovcks9rAP1oN3XW7wu3TyDWq1rw-8,8
|
|
10
|
+
sygmail-0.1.1.dist-info/RECORD,,
|
sygmail-0.1.0.dist-info/RECORD
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
sygmail/__init__.py,sha256=eGoC5SwKCqe1cYhH1LuNPogYeeOTd636Wlnt70nRRB8,83
|
|
2
|
-
sygmail/__main__.py,sha256=MHKZ_ae3fSLGTLUUMOx15fWdeOnJSHhq-zslRP5F5Lc,79
|
|
3
|
-
sygmail/cli.py,sha256=rafYsPIfx55WNnaoO6hgNJZpl0jsxNeZJLxZeIk3hbk,4965
|
|
4
|
-
sygmail/client.py,sha256=lLO72zkAIp2MsO-SYh8_HwdOGP7GNEKaLvPBZ8wlqpE,8190
|
|
5
|
-
sygmail-0.1.0.dist-info/licenses/LICENSE,sha256=Oakmmh4GWfLsNpdR0BBBCzmhIf_3rEeIjrB_hvolczk,1076
|
|
6
|
-
sygmail-0.1.0.dist-info/METADATA,sha256=356x36EyQ6pp3vcC57EjlKNKvzd-FH5frZlIsu77xuk,3755
|
|
7
|
-
sygmail-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
8
|
-
sygmail-0.1.0.dist-info/entry_points.txt,sha256=_6WdaniMLQk9VEx1MnYSNXMIyt7Csce2-PG6mopUGtI,45
|
|
9
|
-
sygmail-0.1.0.dist-info/top_level.txt,sha256=umbnP2FZMQ4N-tovcks9rAP1oN3XW7wu3TyDWq1rw-8,8
|
|
10
|
-
sygmail-0.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|