|
| 1 | +""" Generate responsive HTML emails from Markdown files used in a pelican blog. |
| 2 | +
|
| 3 | +Refer to https://pbpython.com/ for the details. |
| 4 | +
|
| 5 | +""" |
| 6 | +from markdown2 import Markdown |
| 7 | +from pathlib import Path |
| 8 | +from jinja2 import Environment, FileSystemLoader |
| 9 | +from premailer import transform |
| 10 | +from argparse import ArgumentParser |
| 11 | +from bs4 import BeautifulSoup |
| 12 | + |
| 13 | + |
| 14 | +def parse_args(): |
| 15 | + """Parse the command line input |
| 16 | + |
| 17 | + Returns: |
| 18 | + args -- ArgumentParser object |
| 19 | + """ |
| 20 | + parser = ArgumentParser( |
| 21 | + description='Generate HTML email from markdown file') |
| 22 | + parser.add_argument('doc', action='store', help='Markdown input document') |
| 23 | + |
| 24 | + parser.add_argument('-t', |
| 25 | + help='email HTML template', |
| 26 | + default='template.html') |
| 27 | + parser.add_argument( |
| 28 | + '-o', help='output filename. Default is inputfile_email.html') |
| 29 | + args = parser.parse_args() |
| 30 | + return args |
| 31 | + |
| 32 | + |
| 33 | +def create_HTML(config): |
| 34 | + """Read in the source markdown file and convert it to a standalone |
| 35 | + HTML file suitable for emailing |
| 36 | +
|
| 37 | + Arguments: |
| 38 | + config -- ArgumentParser object that contains the input file |
| 39 | + """ |
| 40 | + # Define all the file locations |
| 41 | + in_doc = Path(config.doc) |
| 42 | + if config.o: |
| 43 | + out_file = Path(config.o) |
| 44 | + else: |
| 45 | + out_file = Path.cwd() / f'{in_doc.stem}_email.html' |
| 46 | + template_file = config.t |
| 47 | + |
| 48 | + # Read in the entire file as a list |
| 49 | + # This can be problematic if the file is really large |
| 50 | + with open(in_doc) as f: |
| 51 | + all_content = f.readlines() |
| 52 | + |
| 53 | + # Get the title line and clean it up |
| 54 | + title_line = all_content[0] |
| 55 | + title = f'My Newsletter - {title_line[7:].strip()}' |
| 56 | + |
| 57 | + # Parse out the body from the meta data content at the top of the file |
| 58 | + body_content = all_content[6:] |
| 59 | + |
| 60 | + # Create a markdown object and convert the list of file lines to HTML |
| 61 | + markdowner = Markdown() |
| 62 | + markdown_content = markdowner.convert(''.join(body_content)) |
| 63 | + |
| 64 | + # Set up jinja templates |
| 65 | + env = Environment(loader=FileSystemLoader('.')) |
| 66 | + template = env.get_template(template_file) |
| 67 | + |
| 68 | + # Define the template variables and render |
| 69 | + template_vars = {'email_content': markdown_content, 'title': title} |
| 70 | + raw_html = template.render(template_vars) |
| 71 | + |
| 72 | + # Generate the final output string |
| 73 | + # Inline all the CSS using premailer.transform |
| 74 | + # Use BeautifulSoup to make the formatting nicer |
| 75 | + soup = BeautifulSoup(transform(raw_html), |
| 76 | + 'html.parser').prettify(formatter="html") |
| 77 | + |
| 78 | + # The unsubscribe tag gets mangled. Clean it up. |
| 79 | + final_HTML = str(soup).replace('%7B%7BUnsubscribeURL%7D%7D', |
| 80 | + '{{UnsubscribeURL}}') |
| 81 | + out_file.write_text(final_HTML) |
| 82 | + |
| 83 | + |
| 84 | +if __name__ == '__main__': |
| 85 | + conf = parse_args() |
| 86 | + print('Creating output HTML') |
| 87 | + create_HTML(conf) |
| 88 | + print('Completed') |
0 commit comments