Skip to content

Commit dee1c88

Browse files
committed
rename
1 parent 79e995b commit dee1c88

File tree

6 files changed

+130
-25
lines changed

6 files changed

+130
-25
lines changed

00_markdown_merge.ipynb renamed to 00_core.ipynb

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"metadata": {},
88
"outputs": [],
99
"source": [
10-
"#| default_exp markdown_merge"
10+
"#| default_exp core"
1111
]
1212
},
1313
{
@@ -503,21 +503,9 @@
503503
],
504504
"metadata": {
505505
"kernelspec": {
506-
"display_name": "Python 3 (ipykernel)",
506+
"display_name": "python3",
507507
"language": "python",
508508
"name": "python3"
509-
},
510-
"language_info": {
511-
"codemirror_mode": {
512-
"name": "ipython",
513-
"version": 3
514-
},
515-
"file_extension": ".py",
516-
"mimetype": "text/x-python",
517-
"name": "python",
518-
"nbconvert_exporter": "python",
519-
"pygments_lexer": "ipython3",
520-
"version": "3.12.8"
521509
}
522510
},
523511
"nbformat": 4,

index.ipynb

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": null,
5+
"execution_count": 1,
66
"metadata": {},
77
"outputs": [],
88
"source": [
9-
"#hide\n",
10-
"from markdown_merge.markdown_merge import *"
9+
"#| hide\n",
10+
"from markdown_merge import *"
1111
]
1212
},
1313
{
@@ -49,7 +49,7 @@
4949
},
5050
{
5151
"cell_type": "code",
52-
"execution_count": null,
52+
"execution_count": 2,
5353
"metadata": {},
5454
"outputs": [],
5555
"source": [
@@ -58,7 +58,7 @@
5858
},
5959
{
6060
"cell_type": "code",
61-
"execution_count": null,
61+
"execution_count": 3,
6262
"metadata": {},
6363
"outputs": [],
6464
"source": [
@@ -84,7 +84,7 @@
8484
},
8585
{
8686
"cell_type": "code",
87-
"execution_count": null,
87+
"execution_count": 4,
8888
"metadata": {},
8989
"outputs": [],
9090
"source": [
@@ -101,7 +101,7 @@
101101
},
102102
{
103103
"cell_type": "code",
104-
"execution_count": null,
104+
"execution_count": 5,
105105
"metadata": {},
106106
"outputs": [],
107107
"source": [
@@ -124,7 +124,7 @@
124124
},
125125
{
126126
"cell_type": "code",
127-
"execution_count": null,
127+
"execution_count": 6,
128128
"metadata": {},
129129
"outputs": [
130130
{
@@ -151,13 +151,32 @@
151151
"source": [
152152
"ml.send_msgs()"
153153
]
154+
},
155+
{
156+
"cell_type": "code",
157+
"execution_count": null,
158+
"metadata": {},
159+
"outputs": [],
160+
"source": []
154161
}
155162
],
156163
"metadata": {
157164
"kernelspec": {
158-
"display_name": "python3",
165+
"display_name": "Python 3 (ipykernel)",
159166
"language": "python",
160167
"name": "python3"
168+
},
169+
"language_info": {
170+
"codemirror_mode": {
171+
"name": "ipython",
172+
"version": 3
173+
},
174+
"file_extension": ".py",
175+
"mimetype": "text/x-python",
176+
"name": "python",
177+
"nbconvert_exporter": "python",
178+
"pygments_lexer": "ipython3",
179+
"version": "3.12.8"
161180
}
162181
},
163182
"nbformat": 4,

markdown_merge/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
__version__ = "0.1.0"
2+
from .core import *

markdown_merge/_modidx.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,19 @@
55
'doc_host': 'https://answerdotai.github.io',
66
'git_url': 'https://github.com/answerdotai/markdown_merge/tree/master/',
77
'lib_path': 'markdown_merge'},
8-
'syms': { 'markdown_merge.markdown_merge': { 'markdown_merge.markdown_merge.MarkdownMerge': ( 'markdown_merge.html#markdownmerge',
8+
'syms': { 'markdown_merge.core': { 'markdown_merge.core.MarkdownMerge': ('core.html#markdownmerge', 'markdown_merge/core.py'),
9+
'markdown_merge.core.MarkdownMerge.__init__': ( 'core.html#markdownmerge.__init__',
10+
'markdown_merge/core.py'),
11+
'markdown_merge.core.MarkdownMerge.reset': ('core.html#markdownmerge.reset', 'markdown_merge/core.py'),
12+
'markdown_merge.core.MarkdownMerge.send_msgs': ( 'core.html#markdownmerge.send_msgs',
13+
'markdown_merge/core.py'),
14+
'markdown_merge.core.attach_file': ('core.html#attach_file', 'markdown_merge/core.py'),
15+
'markdown_merge.core.create_multipart_msg': ( 'core.html#create_multipart_msg',
16+
'markdown_merge/core.py'),
17+
'markdown_merge.core.get_addr': ('core.html#get_addr', 'markdown_merge/core.py'),
18+
'markdown_merge.core.md2email': ('core.html#md2email', 'markdown_merge/core.py'),
19+
'markdown_merge.core.smtp_connection': ('core.html#smtp_connection', 'markdown_merge/core.py')},
20+
'markdown_merge.markdown_merge': { 'markdown_merge.markdown_merge.MarkdownMerge': ( 'markdown_merge.html#markdownmerge',
921
'markdown_merge/markdown_merge.py'),
1022
'markdown_merge.markdown_merge.MarkdownMerge.__init__': ( 'markdown_merge.html#markdownmerge.__init__',
1123
'markdown_merge/markdown_merge.py'),

markdown_merge/core.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""API details"""
2+
3+
# AUTOGENERATED! DO NOT EDIT! File to edit: ../00_core.ipynb.
4+
5+
# %% auto 0
6+
__all__ = ['get_addr', 'attach_file', 'create_multipart_msg', 'md2email', 'smtp_connection', 'MarkdownMerge']
7+
8+
# %% ../00_core.ipynb 2
9+
import os,mimetypes,smtplib
10+
11+
from fastcore.utils import *
12+
from email.mime.multipart import MIMEMultipart
13+
from email.mime.text import MIMEText
14+
from email.mime.base import MIMEBase
15+
from email import encoders
16+
17+
from contextlib import contextmanager
18+
from markdown import markdown
19+
from email.headerregistry import Address
20+
from time import sleep
21+
22+
# %% ../00_core.ipynb 6
23+
def get_addr(email, name=None):
24+
"Convert `email` and optional `name` into an email `Address` object"
25+
return Address(email if name is None else name, addr_spec=email)
26+
27+
# %% ../00_core.ipynb 9
28+
def attach_file(msg, f):
29+
"Attach file `f` to message `msg`"
30+
mtype,_ = mimetypes.guess_type(f)
31+
main,sub = (mtype or 'application/octet-stream').split('/', 1)
32+
part = MIMEBase(main, sub)
33+
with open(f, 'rb') as fp: part.set_payload(fp.read())
34+
encoders.encode_base64(part)
35+
part['Content-Disposition'] = f'attachment; filename={Path(f).name}'
36+
msg.attach(part)
37+
38+
# %% ../00_core.ipynb 11
39+
def create_multipart_msg(subj, from_addr, to_addrs, md=None, html=None, attach=None):
40+
"Create a multipart email with markdown text and HTML"
41+
msg = MIMEMultipart('alternative')
42+
msg['Subject'],msg['From'] = subj,str(from_addr)
43+
msg['To'] = ', '.join([str(a) for a in listify(to_addrs)])
44+
if md: msg.attach(MIMEText(md, 'plain'))
45+
if html: msg.attach(MIMEText(html, 'html'))
46+
for f in listify(attach): attach_file(msg, f)
47+
return msg
48+
49+
# %% ../00_core.ipynb 13
50+
def md2email(subj, from_addr, to_addrs, md, attach=None):
51+
"Create a multipart email from markdown"
52+
html = markdown(md)
53+
return create_multipart_msg(subj, from_addr, to_addrs, md=md, html=html, attach=attach)
54+
55+
# %% ../00_core.ipynb 23
56+
@contextmanager
57+
def smtp_connection(host, port, user=None, password=None, use_ssl=True, use_tls=False):
58+
"Context manager for SMTP connection"
59+
conn = smtplib.SMTP_SSL(host, port) if use_ssl else smtplib.SMTP(host, port)
60+
if use_tls and not use_ssl: conn.starttls()
61+
if user and password: conn.login(user, password)
62+
try: yield conn
63+
finally: conn.quit()
64+
65+
# %% ../00_core.ipynb 27
66+
class MarkdownMerge:
67+
"Send templated email merge messages formatted with Markdown"
68+
def __init__(self, addrs, from_addr, subj, msg, smtp_cfg=None, inserts=None, test=False):
69+
self.addrs,self.from_addr,self.subj,self.msg,self.i = addrs,from_addr,subj,msg,0
70+
self.inserts = [{}]*len(addrs) if inserts is None else inserts
71+
self.smtp_cfg,self.test = smtp_cfg,test
72+
73+
def send_msgs(self, pause=0.5):
74+
"Send all unsent messages to `addrs` with `pause` secs between each send"
75+
with smtp_connection(**self.smtp_cfg) as conn:
76+
while self.i < len(self.addrs):
77+
addr,insert = self.addrs[self.i],self.inserts[self.i]
78+
msg = self.msg.format(**insert)
79+
eml = md2email(self.subj, self.from_addr, addr, md=msg)
80+
if self.test: print(f"To: {addr}\n{'-'*40}\n{msg}\n{'='*40}\n")
81+
else: conn.send_message(eml); sleep(pause)
82+
self.i += 1
83+
if self.i%100==0: print(self.i)
84+
85+
def reset(self): self.i=0

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name="markdown_merge"
7-
requires-python=">=3.6"
7+
requires-python=">=3.10"
88
dynamic = [ "keywords", "description", "version", "dependencies", "optional-dependencies", "readme", "license", "authors", "classifiers", "entry-points", "scripts", "urls"]
99

1010
[tool.uv]

0 commit comments

Comments
 (0)