markdown-merge 0.1.0__tar.gz → 0.1.4__tar.gz

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.

Potentially problematic release.


This version of markdown-merge might be problematic. Click here for more details.

Files changed (23) hide show
  1. markdown_merge-0.1.4/MANIFEST.in +5 -0
  2. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/PKG-INFO +7 -13
  3. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/README.md +0 -5
  4. markdown_merge-0.1.4/markdown_merge/__init__.py +2 -0
  5. markdown_merge-0.1.4/markdown_merge/_modidx.py +19 -0
  6. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/markdown_merge/core.py +8 -8
  7. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/markdown_merge.egg-info/PKG-INFO +7 -13
  8. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/markdown_merge.egg-info/SOURCES.txt +2 -2
  9. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/markdown_merge.egg-info/requires.txt +1 -1
  10. markdown_merge-0.1.4/pyproject.toml +3 -0
  11. markdown_merge-0.1.4/settings.ini +39 -0
  12. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/setup.py +22 -21
  13. markdown_merge-0.1.0/markdown_merge/__init__.py +0 -2
  14. markdown_merge-0.1.0/markdown_merge/_modidx.py +0 -37
  15. markdown_merge-0.1.0/markdown_merge/_nbdev.py +0 -9
  16. markdown_merge-0.1.0/markdown_merge/markdown_merge.py +0 -85
  17. markdown_merge-0.1.0/pyproject.toml +0 -11
  18. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/LICENSE +0 -0
  19. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/markdown_merge.egg-info/dependency_links.txt +0 -0
  20. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/markdown_merge.egg-info/entry_points.txt +0 -0
  21. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/markdown_merge.egg-info/not-zip-safe +0 -0
  22. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/markdown_merge.egg-info/top_level.txt +0 -0
  23. {markdown_merge-0.1.0 → markdown_merge-0.1.4}/setup.cfg +0 -0
@@ -0,0 +1,5 @@
1
+ include settings.ini
2
+ include LICENSE
3
+ include CONTRIBUTING.md
4
+ include README.md
5
+ recursive-exclude * __pycache__
@@ -1,24 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown_merge
3
- Version: 0.1.0
4
- Summary: Send templated emails in markdown
5
- Home-page: https://github.com/answerdotai/markdown_merge/tree/master/
3
+ Version: 0.1.4
4
+ Summary: Send email using markdown
5
+ Home-page: https://github.com/AnswerDotAI/markdown_merge
6
6
  Author: Jeremy Howard
7
- Author-email: info@fast.ai
7
+ Author-email: github@jhoward.fastmail.fm
8
8
  License: Apache Software License 2.0
9
9
  Keywords: email mail markdown template
10
- Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: Apache Software License
13
12
  Classifier: Natural Language :: English
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
- Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: License :: OSI Approved :: Apache Software License
18
17
  Requires-Python: >=3.10
19
18
  Description-Content-Type: text/markdown
20
19
  License-File: LICENSE
21
- Requires-Dist: packaging
20
+ Requires-Dist: fastcore
22
21
  Requires-Dist: markdown
23
22
  Provides-Extra: dev
24
23
  Dynamic: author
@@ -40,11 +39,6 @@ Dynamic: summary
40
39
 
41
40
  <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
42
41
 
43
- ``` python
44
- #hide
45
- from markdown_merge.markdown_merge import *
46
- ```
47
-
48
42
  ## Install
49
43
 
50
44
  `pip install markdown_merge`
@@ -3,11 +3,6 @@
3
3
 
4
4
  <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
5
5
 
6
- ``` python
7
- #hide
8
- from markdown_merge.markdown_merge import *
9
- ```
10
-
11
6
  ## Install
12
7
 
13
8
  `pip install markdown_merge`
@@ -0,0 +1,2 @@
1
+ __version__ = "0.1.4"
2
+ from .core import *
@@ -0,0 +1,19 @@
1
+ # Autogenerated by nbdev
2
+
3
+ d = { 'settings': { 'branch': 'master',
4
+ 'doc_baseurl': '/markdown_merge',
5
+ 'doc_host': 'https://AnswerDotAI.github.io',
6
+ 'git_url': 'https://github.com/AnswerDotAI/markdown_merge',
7
+ 'lib_path': 'markdown_merge'},
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')}}}
@@ -1,11 +1,11 @@
1
1
  """API details"""
2
2
 
3
- # AUTOGENERATED! DO NOT EDIT! File to edit: ../00_core.ipynb.
3
+ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.
4
4
 
5
5
  # %% auto 0
6
6
  __all__ = ['get_addr', 'attach_file', 'create_multipart_msg', 'md2email', 'smtp_connection', 'MarkdownMerge']
7
7
 
8
- # %% ../00_core.ipynb 2
8
+ # %% ../nbs/00_core.ipynb
9
9
  import os,mimetypes,smtplib
10
10
 
11
11
  from fastcore.utils import *
@@ -19,12 +19,12 @@ from markdown import markdown
19
19
  from email.headerregistry import Address
20
20
  from time import sleep
21
21
 
22
- # %% ../00_core.ipynb 6
22
+ # %% ../nbs/00_core.ipynb
23
23
  def get_addr(email, name=None):
24
24
  "Convert `email` and optional `name` into an email `Address` object"
25
25
  return Address(email if name is None else name, addr_spec=email)
26
26
 
27
- # %% ../00_core.ipynb 9
27
+ # %% ../nbs/00_core.ipynb
28
28
  def attach_file(msg, f):
29
29
  "Attach file `f` to message `msg`"
30
30
  mtype,_ = mimetypes.guess_type(f)
@@ -35,7 +35,7 @@ def attach_file(msg, f):
35
35
  part['Content-Disposition'] = f'attachment; filename={Path(f).name}'
36
36
  msg.attach(part)
37
37
 
38
- # %% ../00_core.ipynb 11
38
+ # %% ../nbs/00_core.ipynb
39
39
  def create_multipart_msg(subj, from_addr, to_addrs, md=None, html=None, attach=None):
40
40
  "Create a multipart email with markdown text and HTML"
41
41
  msg = MIMEMultipart('alternative')
@@ -46,13 +46,13 @@ def create_multipart_msg(subj, from_addr, to_addrs, md=None, html=None, attach=N
46
46
  for f in listify(attach): attach_file(msg, f)
47
47
  return msg
48
48
 
49
- # %% ../00_core.ipynb 13
49
+ # %% ../nbs/00_core.ipynb
50
50
  def md2email(subj, from_addr, to_addrs, md, attach=None):
51
51
  "Create a multipart email from markdown"
52
52
  html = markdown(md)
53
53
  return create_multipart_msg(subj, from_addr, to_addrs, md=md, html=html, attach=attach)
54
54
 
55
- # %% ../00_core.ipynb 23
55
+ # %% ../nbs/00_core.ipynb
56
56
  @contextmanager
57
57
  def smtp_connection(host, port, user=None, password=None, use_ssl=True, use_tls=False):
58
58
  "Context manager for SMTP connection"
@@ -62,7 +62,7 @@ def smtp_connection(host, port, user=None, password=None, use_ssl=True, use_tls=
62
62
  try: yield conn
63
63
  finally: conn.quit()
64
64
 
65
- # %% ../00_core.ipynb 27
65
+ # %% ../nbs/00_core.ipynb
66
66
  class MarkdownMerge:
67
67
  "Send templated email merge messages formatted with Markdown"
68
68
  def __init__(self, addrs, from_addr, subj, msg, smtp_cfg=None, inserts=None, test=False):
@@ -1,24 +1,23 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown_merge
3
- Version: 0.1.0
4
- Summary: Send templated emails in markdown
5
- Home-page: https://github.com/answerdotai/markdown_merge/tree/master/
3
+ Version: 0.1.4
4
+ Summary: Send email using markdown
5
+ Home-page: https://github.com/AnswerDotAI/markdown_merge
6
6
  Author: Jeremy Howard
7
- Author-email: info@fast.ai
7
+ Author-email: github@jhoward.fastmail.fm
8
8
  License: Apache Software License 2.0
9
9
  Keywords: email mail markdown template
10
- Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: Apache Software License
13
12
  Classifier: Natural Language :: English
14
13
  Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
- Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: License :: OSI Approved :: Apache Software License
18
17
  Requires-Python: >=3.10
19
18
  Description-Content-Type: text/markdown
20
19
  License-File: LICENSE
21
- Requires-Dist: packaging
20
+ Requires-Dist: fastcore
22
21
  Requires-Dist: markdown
23
22
  Provides-Extra: dev
24
23
  Dynamic: author
@@ -40,11 +39,6 @@ Dynamic: summary
40
39
 
41
40
  <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->
42
41
 
43
- ``` python
44
- #hide
45
- from markdown_merge.markdown_merge import *
46
- ```
47
-
48
42
  ## Install
49
43
 
50
44
  `pip install markdown_merge`
@@ -1,12 +1,12 @@
1
1
  LICENSE
2
+ MANIFEST.in
2
3
  README.md
3
4
  pyproject.toml
5
+ settings.ini
4
6
  setup.py
5
7
  markdown_merge/__init__.py
6
8
  markdown_merge/_modidx.py
7
- markdown_merge/_nbdev.py
8
9
  markdown_merge/core.py
9
- markdown_merge/markdown_merge.py
10
10
  markdown_merge.egg-info/PKG-INFO
11
11
  markdown_merge.egg-info/SOURCES.txt
12
12
  markdown_merge.egg-info/dependency_links.txt
@@ -1,4 +1,4 @@
1
- packaging
1
+ fastcore
2
2
  markdown
3
3
 
4
4
  [dev]
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64.0"]
3
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,39 @@
1
+ [DEFAULT]
2
+ repo = markdown_merge
3
+ lib_name = markdown_merge
4
+ version = 0.1.4
5
+ min_python = 3.10
6
+ license = apache2
7
+ black_formatting = False
8
+ requirements = fastcore markdown
9
+ doc_path = _docs
10
+ lib_path = markdown_merge
11
+ nbs_path = nbs
12
+ recursive = True
13
+ tst_flags = notest
14
+ put_version_in_init = True
15
+ update_pyproject = True
16
+ branch = master
17
+ custom_sidebar = False
18
+ doc_host = https://AnswerDotAI.github.io
19
+ doc_baseurl = /markdown_merge
20
+ git_url = https://github.com/AnswerDotAI/markdown_merge
21
+ title = markdown_merge
22
+ audience = Developers
23
+ author = Jeremy Howard
24
+ author_email = github@jhoward.fastmail.fm
25
+ copyright = 2025 onwards, Jeremy Howard
26
+ description = Send email using markdown
27
+ keywords = email mail markdown template
28
+ language = English
29
+ status = 3
30
+ user = AnswerDotAI
31
+ cell_number = False
32
+ readme_nb = index.ipynb
33
+ allowed_metadata_keys =
34
+ allowed_cell_metadata_keys =
35
+ jupyter_hooks = False
36
+ clean_ids = True
37
+ clear_all = False
38
+ skip_procs =
39
+
@@ -1,11 +1,11 @@
1
1
  from pkg_resources import parse_version
2
2
  from configparser import ConfigParser
3
- import setuptools,re,sys
3
+ import setuptools, shlex
4
4
  assert parse_version(setuptools.__version__)>=parse_version('36.2')
5
5
 
6
6
  # note: all settings are in settings.ini; edit there, not here
7
7
  config = ConfigParser(delimiters=['='])
8
- config.read('settings.ini')
8
+ config.read('settings.ini', encoding='utf-8')
9
9
  cfg = config['DEFAULT']
10
10
 
11
11
  cfg_keys = 'version description keywords author author_email'.split()
@@ -13,46 +13,46 @@ expected = cfg_keys + "lib_name user branch license status min_python audience l
13
13
  for o in expected: assert o in cfg, "missing expected setting: {}".format(o)
14
14
  setup_cfg = {o:cfg[o] for o in cfg_keys}
15
15
 
16
- if len(sys.argv)>1 and sys.argv[1]=='version':
17
- print(setup_cfg['version'])
18
- exit()
19
-
20
16
  licenses = {
21
17
  'apache2': ('Apache Software License 2.0','OSI Approved :: Apache Software License'),
18
+ 'mit': ('MIT License', 'OSI Approved :: MIT License'),
19
+ 'gpl2': ('GNU General Public License v2', 'OSI Approved :: GNU General Public License v2 (GPLv2)'),
20
+ 'gpl3': ('GNU General Public License v3', 'OSI Approved :: GNU General Public License v3 (GPLv3)'),
21
+ 'bsd3': ('BSD License', 'OSI Approved :: BSD License'),
22
22
  }
23
23
  statuses = [ '1 - Planning', '2 - Pre-Alpha', '3 - Alpha',
24
24
  '4 - Beta', '5 - Production/Stable', '6 - Mature', '7 - Inactive' ]
25
- py_versions = '3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13'.split()
26
- min_python = cfg['min_python']
27
- lic = licenses[cfg['license']]
25
+ py_versions = '3.6 3.7 3.8 3.9 3.10 3.11 3.12'.split()
28
26
 
29
- requirements = ['packaging']
30
- if cfg.get('requirements'): requirements += cfg.get('requirements','').split()
31
- if cfg.get('pip_requirements'): requirements += cfg.get('pip_requirements','').split()
27
+ requirements = shlex.split(cfg.get('requirements', ''))
28
+ if cfg.get('pip_requirements'): requirements += shlex.split(cfg.get('pip_requirements', ''))
29
+ min_python = cfg['min_python']
30
+ lic = licenses.get(cfg['license'].lower(), (cfg['license'], None))
32
31
  dev_requirements = (cfg.get('dev_requirements') or '').split()
33
32
 
34
- long_description = open('README.md', encoding="utf8").read()
35
- # ![png](docs/images/output_13_0.png)
36
- for ext in ['png', 'svg']:
37
- long_description = re.sub(r'!\['+ext+'\]\((.*)\)', '!['+ext+']('+'https://raw.githubusercontent.com/{}/{}'.format(cfg['user'],cfg['lib_name'])+'/'+cfg['branch']+'/\\1)', long_description)
38
- long_description = re.sub(r'src=\"(.*)\.'+ext+'\"', 'src=\"https://raw.githubusercontent.com/{}/{}'.format(cfg['user'],cfg['lib_name'])+'/'+cfg['branch']+'/\\1.'+ext+'\"', long_description)
33
+ package_data = dict()
34
+ pkg_data = cfg.get('package_data', None)
35
+ if pkg_data:
36
+ package_data[cfg['lib_name']] = pkg_data.split() # split as multiple files might be listed
37
+ # Add package data to setup_cfg for setuptools.setup(..., **setup_cfg)
38
+ setup_cfg['package_data'] = package_data
39
39
 
40
40
  setuptools.setup(
41
- name = 'markdown-merge',
41
+ name = cfg['lib_name'],
42
42
  license = lic[0],
43
43
  classifiers = [
44
44
  'Development Status :: ' + statuses[int(cfg['status'])],
45
45
  'Intended Audience :: ' + cfg['audience'].title(),
46
- 'License :: ' + lic[1],
47
46
  'Natural Language :: ' + cfg['language'].title(),
48
- ] + ['Programming Language :: Python :: '+o for o in py_versions[py_versions.index(min_python):]],
47
+ ] + ['Programming Language :: Python :: '+o for o in py_versions[py_versions.index(min_python):]] + (['License :: ' + lic[1] ] if lic[1] else []),
49
48
  url = cfg['git_url'],
50
49
  packages = setuptools.find_packages(),
51
50
  include_package_data = True,
52
51
  install_requires = requirements,
53
52
  extras_require={ 'dev': dev_requirements },
53
+ dependency_links = cfg.get('dep_links','').split(),
54
54
  python_requires = '>=' + cfg['min_python'],
55
- long_description = long_description,
55
+ long_description = open('README.md', encoding='utf-8').read(),
56
56
  long_description_content_type = 'text/markdown',
57
57
  zip_safe = False,
58
58
  entry_points = {
@@ -61,3 +61,4 @@ setuptools.setup(
61
61
  },
62
62
  **setup_cfg)
63
63
 
64
+
@@ -1,2 +0,0 @@
1
- __version__ = "0.1.0"
2
- from .core import *
@@ -1,37 +0,0 @@
1
- # Autogenerated by nbdev
2
-
3
- d = { 'settings': { 'branch': 'master',
4
- 'doc_baseurl': '/',
5
- 'doc_host': 'https://answerdotai.github.io',
6
- 'git_url': 'https://github.com/answerdotai/markdown_merge/tree/master/',
7
- 'lib_path': 'markdown_merge'},
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',
21
- 'markdown_merge/markdown_merge.py'),
22
- 'markdown_merge.markdown_merge.MarkdownMerge.__init__': ( 'markdown_merge.html#markdownmerge.__init__',
23
- 'markdown_merge/markdown_merge.py'),
24
- 'markdown_merge.markdown_merge.MarkdownMerge.reset': ( 'markdown_merge.html#markdownmerge.reset',
25
- 'markdown_merge/markdown_merge.py'),
26
- 'markdown_merge.markdown_merge.MarkdownMerge.send_msgs': ( 'markdown_merge.html#markdownmerge.send_msgs',
27
- 'markdown_merge/markdown_merge.py'),
28
- 'markdown_merge.markdown_merge.attach_file': ( 'markdown_merge.html#attach_file',
29
- 'markdown_merge/markdown_merge.py'),
30
- 'markdown_merge.markdown_merge.create_multipart_msg': ( 'markdown_merge.html#create_multipart_msg',
31
- 'markdown_merge/markdown_merge.py'),
32
- 'markdown_merge.markdown_merge.get_addr': ( 'markdown_merge.html#get_addr',
33
- 'markdown_merge/markdown_merge.py'),
34
- 'markdown_merge.markdown_merge.md2email': ( 'markdown_merge.html#md2email',
35
- 'markdown_merge/markdown_merge.py'),
36
- 'markdown_merge.markdown_merge.smtp_connection': ( 'markdown_merge.html#smtp_connection',
37
- 'markdown_merge/markdown_merge.py')}}}
@@ -1,9 +0,0 @@
1
- #AUTOGENERATED BY NBDEV! DO NOT EDIT!
2
-
3
- __all__ = ["index", "modules"]
4
-
5
- index = {"get_addr": "00_markdown_merge.ipynb",
6
- "md2email": "00_markdown_merge.ipynb",
7
- "MarkdownMerge": "00_markdown_merge.ipynb"}
8
-
9
- modules = ["markdown_merge.py"]
@@ -1,85 +0,0 @@
1
- """API details"""
2
-
3
- # AUTOGENERATED! DO NOT EDIT! File to edit: ../00_markdown_merge.ipynb.
4
-
5
- # %% auto 0
6
- __all__ = ['get_addr', 'attach_file', 'create_multipart_msg', 'md2email', 'smtp_connection', 'MarkdownMerge']
7
-
8
- # %% ../00_markdown_merge.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_markdown_merge.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_markdown_merge.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_markdown_merge.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_markdown_merge.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_markdown_merge.ipynb 22
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_markdown_merge.ipynb 26
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
@@ -1,11 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=64.0"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name="markdown_merge"
7
- requires-python=">=3.10"
8
- dynamic = [ "keywords", "description", "version", "dependencies", "optional-dependencies", "readme", "license", "authors", "classifiers", "entry-points", "scripts", "urls"]
9
-
10
- [tool.uv]
11
- cache-keys = [{ file = "pyproject.toml" }, { file = "settings.ini" }, { file = "setup.py" }]
File without changes
File without changes