any easy way to author HTML email? Yes: found that I can do so in both in and in thunderbird.

Questions I have:

https://news.ycombinator.com/item?id=6169040 -> https://github.com/charlierguo/gmail

git clone https://github.com/charlierguo/gmail.git

To install:

pip install git+https://github.com/charlierguo/gmail.git

/Users/raymondyee/C/src/gmail

to use -- I will create a specific password for this use at https://accounts.google.com/b/0/IssuedAuthSubTokens?hl=en

SMTP

specialized gmail library in Python

creating Evernote notes in a series of examples with a rising level of complexity:

  • simple text
  • ENML with no image references
  • ENML with attachments

Question: what aspects of the conversion from HTML to ENML + resources can be handled by emailing HTML email to evernote? Specifically:

  • Are external img URL references done for you by Evernote?
  • Do references to external CSS stylesheets (or even embedded CSS) -- CSS that is not inlined -- converted to inline CSS for us?
  • How about not well-formed HTML?

In [ ]:
from settings import (gmail_username, gmail_password, evernote_email)
import gmail

def gmail_sent_to_myself(gmail_username, gmail_password):

    g = gmail.login(gmail_username, gmail_password)
    assert g.logged_in # Should be True, AuthenticationError if login fails
    
    emails = g.inbox().mail(fr=gmail_username, prefetch=True)
    return emails

In [ ]:
emails = gmail_sent_to_myself(gmail_username, gmail_password)
email = emails[0]
email.subject, email.body

how are attachments handled? mimetypes? Come back to look at http://yuji.wordpress.com/2011/06/22/python-imaplib-imap-example-with-gmail/

Generating email to send to evernote

simple example -- non HTML email w/ no attachment


In [ ]:
# based on http://stackoverflow.com/a/9274387/7782

from email.header    import Header
from email.mime.text import MIMEText
from smtplib         import SMTP_SSL

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText


def simple_email_send(host, login, password, text, subject, from_, to, encoding='utf-8', port=465, timeout=10,
                     debug_level=0):
    """
    e.g., host smtp.gmail.com
    login, to are email addresses
    """
    
    # create message
    msg = MIMEText(subject, _charset=encoding)
    msg['Subject'] = Header(subject, encoding)
    msg['From'] = from_
    msg['To'] = to

    s = SMTP_SSL(host, port, timeout=timeout)
    s.set_debuglevel(debug_level)
    try:
        s.login(login, password)
        s.sendmail(msg['From'], msg['To'], msg.as_string())
    finally:
        s.quit()

In [ ]:
simple_email_send('smtp.gmail.com', gmail_username, gmail_password, 
                 text = """You're in luck, my friend.""",
                 subject='Hello from your friendly Nigerian prince',
                 from_ = gmail_username,
                 to = gmail_username)

In [ ]:
def send_email_text_html(host, login, password, text, subject, from_, to, html=None, encoding='utf-8', port=465, timeout=10,
                     debug_level=0):
    """
    e.g., host smtp.gmail.com
    login, to are email addresses
    """

    # create message
    
    if html is not None:
        # Create message container - the correct MIME type is multipart/alternative.
        msg = MIMEMultipart('alternative')
    else:
        msg = MIMEText(subject, _charset=encoding)
        
    msg['Subject'] = Header(subject, encoding)
    msg['From'] = from_
    msg['To'] = to

    if html is not None:
        # Record the MIME types of both parts - text/plain and text/html.
        part1 = MIMEText(text, 'plain', _charset=encoding)
        part2 = MIMEText(html, 'html', _charset=encoding)

        # Attach parts into message container.
        # According to RFC 2046, the last part of a multipart message, in this case
        # the HTML message, is best and preferred.
        msg.attach(part1)
        msg.attach(part2)

    s = SMTP_SSL(host, port, timeout=timeout)
    s.set_debuglevel(debug_level)
    try:
        s.login(login, password)
        s.sendmail(msg['From'], msg['To'], msg.as_string())
    finally:
        s.quit()

In [ ]:
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttp://www.python.org"
html = """\
<html>
  <head>
    <title>An email</title>
  </head>
  <body>
    <p>Hi!<br/>
       How are you?<br/>
       <span style="color:red">styled span</span><br/>
       Here is the <a href="http://www.python.org">link</a> you wanted.
    </p>
    <img src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/Johann_Sebastian_Bach.jpg/220px-Johann_Sebastian_Bach.jpg"/>
  </body>
</html>
"""

send_email_text_html('smtp.gmail.com', gmail_username, gmail_password, 
                 text = text,
                 subject='send_email_text_html TEST',
                 from_ = gmail_username,
                 to = gmail_username,
                 html = html)

In [ ]:
# this routine works when html is None too

send_email_text_html('smtp.gmail.com', gmail_username, gmail_password, 
                 text = """You're in luck, my friend.""",
                 subject='Hello from your friendly Nigerian prince',
                 from_ = gmail_username,
                 to = gmail_username,
                 html=None)

In [ ]:
# next question:  inlining of CSS done for us by Evernote?  Answer is NO.

Working conclusion: we have to do our own CSS inlining for email and for Evernote


In [ ]:
!pip freeze | grep pynliner

In [ ]:
# http://pythonhosted.org/pynliner/
# pip install pynliner

import pynliner
html = u'<style>h1 { color:#ffcc00; }</style><h1>Hello World!</h1>'

output = pynliner.fromString(html)
output

In [ ]:
from pynliner import Pynliner

html = "<h1>Hello World!</h1>"
css = "h1 { color:#ffcc00; }"
p = Pynliner()
p.from_string(html).with_cssString(css)
p.run()

In [ ]:
# Python 2

from urllib2 import urlopen

url = 'http://mashupguide.net/1.0/html/'
fallback_encoding = 'UTF-8'

response = urlopen(url)
the_page = response.read()

encoding = response.headers.getparam("charset")
if encoding is None:
    encoding = fallback_encoding
    
content = the_page.decode(encoding)

print (encoding, type(content), content[:100])

In [ ]:
import requests

url = 'http://mashupguide.net/1.0/html/'
r = requests.get(url)
r.headers

In [ ]:
from pynliner import Pynliner

p = Pynliner()
p.from_url('http://mashupguide.net/1.0/html/')
html = p.run()

In [ ]:
send_email_text_html('smtp.gmail.com', gmail_username, gmail_password, 
                 text = text,
                 subject='mashupguide toc',
                 from_ = gmail_username,
                 to = evernote_email,
                 html = html)

premailer

https://github.com/peterbe/premailer

pip install premailer

In [ ]:
!pip freeze | grep premailer

In [ ]:
from premailer import transform

print transform("""
         <html>
         <style type="text/css">
         h1 { border:1px solid black }
            p { color:red;}
            p::first-letter { float:left; }
         </style>
         <h1 style="font-weight:bolder">Peter</h1>
             <p>Hej</p>
         </html>""")

In [ ]:
url = "http://mashupguide.net/1.0/html/"

import requests
r = requests.get(url=url)
r

In [ ]:
r.text.encode('ascii', 'ignore')

In [ ]:
import requests
from premailer import transform

url = "http://mashupguide.net/1.0/html/"

r = requests.get(url=url)
# transforming to ascii to get around what seems to be a bug in premailer
t = transform(r.text.encode('ascii', 'ignore'), base_url=url)
print t

In [ ]:
# based on http://docs.python.org/2/library/email-examples.html

import smtplib
from smtplib import SMTP_SSL

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# me == my email address
# you == recipient's email address

from settings import (gmail_username, gmail_password, evernote_email)

me = gmail_username
you = evernote_email

# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you

# Create the body of the message (a plain-text and an HTML version).

text = url

import requests
from premailer import transform

url = "http://mashupguide.net/1.0/html/"

r = requests.get(url=url)
# work around to do ascii decoding
html = transform(r.text.encode('ascii', 'ignore'), base_url=url)


# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')

# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)

login, password = gmail_username, gmail_password
# send it via gmail
s = SMTP_SSL('smtp.gmail.com', 465, timeout=10)
s.set_debuglevel(0)
try:
    s.login(login, password)
    s.sendmail(msg['From'], msg['To'], msg.as_string())
finally:
    s.quit()

problem: although the relative URIs are converted to absolute URIs, premailer doesn't handle external CSS files: https://github.com/peterbe/premailer/issues/6

Solution: come back to parse HTML and turn external CSS references to embedded style: http://lxml.de/parsing.html


In [ ]:
# based on http://docs.python.org/2/library/email-examples.html

import smtplib
from smtplib import SMTP_SSL

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# me == my email address
# you == recipient's email address

from settings import (gmail_username, gmail_password, evernote_email)

me = gmail_username
you = evernote_email

# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you

# Create the body of the message (a plain-text and an HTML version).

text = url

import requests
from premailer import transform

mashupsource = open("mashupguidetoc.html").read()

html = transform(mashupsource, base_url=url)


# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')

# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)

login, password = gmail_username, gmail_password
# send it via gmail
s = SMTP_SSL('smtp.gmail.com', 465, timeout=10)
s.set_debuglevel(0)
try:
    s.login(login, password)
    s.sendmail(msg['From'], msg['To'], msg.as_string())
finally:
    s.quit()

In [ ]:
print html

instyle-mailer


In [ ]: