Send a message in Python with graphics and text

Recently, many communication tools have been used, such as corporate WeChat robots, pins, WeChat public number interfaces (unauthenticated subscription public numbers), which are too weak for mail.There are no richer versions, for example.Of course, it doesn't mean that the better the presentation, the better the appointment, which depends on personal circumstances, but I just need a richer presentation, and eventually I returned to the mail, which is really fragrant!

And I don't have the right microsignal to log on to the interface of personal microsignal. If the web version of the WeChat is not enveloped, I think this is the best way to combine presentation with message timeliness.

Environmental Science

Although it's easy to be compatible with Python2 and Python3 just by sending an email, hug Python3. I don't have a compatible way to write python2 here, so I need python3 or more.

Format of mail

Mail is in two main formats: plain and html

plain is like normal text, no formatting.

As its name implies, html is in HTML format, which is equivalent to a message being a static web page. This makes it very playable. You can control the presentation through css.

Note: Although the css syntax here is the same, it is not certain whether it will exactly match the browser rendering results.

Then someone might ask, what do I do with a dynamic web page? Send a link?

Mailbox account

Whether it is QQ mailbox or NetEase mailbox, there is no problem. The important thing is that there is an account name and password that can send mail through the smtp server, everybody Baidu here.

Code to send mail

Because the code to send the mail is the same in each of the following steps, the line is pasted out

def send_email(msg, mail_to, smtp_host, smtp_username, smtp_password, subject, from_):
    msg["Subject"] = Header(subject, "utf-8")
    msg["From"] = Header(from_, "utf-8")
    if not isinstance(mail_to, list):
        mail_to = [mail_to]
    msg["To"] = COMMASPACE.join(mail_to)

    try:
        print("Preparing to connect smtp Mail Server: %s" % smtp_host)
        client = smtplib.SMTP(smtp_host)
        print("Connection Successful")
        # client = smtplib.SMTP("localhost")
        # client.set_debuglevel(1)
        # print(self.mail_user, self.mail_pass)
        client.login(smtp_username, smtp_password)
        print("Login Successful")
        # print("=====>", self.mail_from, mail_to)
        print("Through Mailbox[%s]Send mail to %s" % (smtp_username, COMMASPACE.join(mail_to)))
        client.sendmail(smtp_username, mail_to, msg.as_string())
        print("Send Successfully...")
        return True
    except Exception:
        print("Failed to send mail")
    finally:
        client.quit()

If you have problems sending mail, you canClient.set_The comment for debug level (1) is cancelled, which shows enough debug information to troubleshoot the problem.

Send local pictures

Sending pictures here means that pictures are embedded in the mail instead of appearing as attachments.

The results are as follows:

The code is as follows:

EMAIL_IMAGE_TEMPLATE = """<html>
<head>
<title>Page Title</title>
</head>
<body>
<h3>This is a picture</h3>
<p><img src="cid:{{image_name}}" height="112" width="200" ></p>
</body>
</html>
"""

def create_image_eamil_contant(fp):
    tpl = Template(EMAIL_IMAGE_TEMPLATE)
    if not path.exists(fp):
        sys.exit("The map to be sent does not exist")

    msg = MIMEMultipart("related")
    image_name = "demo"

    with open(fp, "rb") as rf:
        mime_image = MIMEImage(rf.read())
        # Note: parentheses must be <>
        mime_image.add_header("Content-ID", "<%s>" % image_name)
        msg.attach(mime_image)

    # Render mail text content
    text = tpl.render(image_name=image_name)
    msg_alternative = MIMEMultipart("alternative")
    msg_alternative.attach(MIMEText(text, "html", "utf-8"))

    msg.attach(msg_alternative)

    return msg

If you've used python's web framework, you must be familiar with rendering text, because most web frameworks support text rendering, which is jinja2 used here.

Send program generated photos

Actually, there is no difference between this and the above. The only difference is whether to save it locally. Since I can send a local picture, will I save it locally and then follow the above method soon? First of all, this method is OK, but with one more IO, why should I put the things that can be solved in memory locally?

This is mainly the case when the picture is returned from another interface or when it is generated in real time.It's easy, but it's interesting to talk about it.

The simulation here is based on the assumption that multiple base64-encoded pictures are captured online and need to be grouped together and sent directly without saving locally.

This base64-encoded picture has been saved locally under the name demo_base64.txt

The results are as follows:

The code is as follows:

EMAIL_ONLINE_IMAGE_TEMPLATE = """<html>
<head>
<title>Page Title</title>
</head>
<body>
<h3>This is a picture</h3>
<p><img src="cid:{{image_name}}" ></p>
</body>
</html>
"""

def create_online_image_content():
    from PIL import Image

    tpl = Template(EMAIL_ONLINE_IMAGE_TEMPLATE)
    fp = "demo_base64.txt"
    if not path.exists(fp):
        sys.exit("To send base64 Coded picture does not exist")

    msg = MIMEMultipart("related")
    image_name = "demo"

    with open(fp, "rb") as rf:
        base64_data = rf.read()
        img_data = base64.b64decode(base64_data)
        # Because the open method requires a file-like file object, and the object type we decoded is the bytes type
        # The bytes type does not have a read, close method for file objects, so we need to wrap it around with a BytesIO object, which returns a file-like file object
        img = Image.open(BytesIO(img_data))
        img_width, img_height = img.size

        repeat_times = 5
        # compose images
        ret_img  = Image.new(img.mode, (img_width, img_height * repeat_times))
        for index in range(repeat_times):
            ret_img.paste(img, box=(0, index * img_height))

        # Because MIMEImage requires a bytes object, we need to get the binary data encoded by the picture instead of the array data of the picture
        img_bytes = BytesIO()
        # If you do not specify a picture format, you will get an error because you do not have a file name
        ret_img.save(img_bytes, "png")

        mime_image = MIMEImage(img_bytes.getvalue())
        # Note: parentheses must be <>
        mime_image.add_header("Content-ID", "<%s>" % image_name)
        msg.attach(mime_image)

    # Render mail text content
    text = tpl.render(image_name=image_name)
    msg_alternative = MIMEMultipart("alternative")
    msg_alternative.attach(MIMEText(text, "html", "utf-8"))

    msg.attach(msg_alternative)

    return msg

One interesting point here is that BytesIO is used to simulate a file-like object.PIL needs to be installed here

Send a Styled Static Web Page

The previous code sufficiently illustrates what happened to the picture, as demonstrated by a css-style table

The results are as follows:

The code is as follows:

EMAIL_TEMPLATE = """<html>
<head>
    <style type="text/css">
        table
        {
            border-collapse: collapse;
            margin: 0 auto;
            text-align: center;
        }

        table td, table th
        {
            border: 1px solid #cad9ea;
            color: #666;
            height: 30px;
        }

        table thead th
        {
            background-color: #CCE8EB;
            width: 100px;
        }

        table tr:nth-child(odd)
        {
            background: #fff;
        }

        table tr:nth-child(even)
        {
            background: #F5FAFA;
        }
    </style> 
</head>
<body>
<p>There are a total of the following{{record_size}}Bar data</p>
<table width="90%" class="table">
    <thead>
        <tr>
        {% for label in labels %}
            <th>{{label}}</th>
        {% endfor %}
        </tr>
    </thead>
    <tbody>
{% for item in items %}
    <tr>
    {% for value in item %}
        <td>{{value}}</td>
    {% endfor %}
    </tr>
{% endfor %}
    </tbody>
</table>
</html>"""

def create_html_content():
    tpl = Template(EMAIL_TEMPLATE)

    record_size = 10
    label_size = 5
    labels = ["label-%s" % i for i in range(label_size)]
    items = []

    for _ in range(record_size):
        item = ["item-%s" % value_index for value_index in range(label_size)]
        items.append(item)

    text = tpl.render(record_size=record_size, items=items, labels=labels)
    msg = MIMEText(text, "html", "utf-8")
    return msg

Source code address

https://github.com/youerning/blog/tree/master/sendmail

If you're looking forward to future articles, you can focus on my WeChat Public Number (Ear Notes), Headline Number (Ear Notes), github.

Postnote

It's also a good way to send an attachment, such as a generated PDF, which is a great file format.But PDF is not used for the time being, so I'll have a chance to talk about it later.Finally, it should be noted that the display effect on the mobile phone side is different from that on the web page of the computer.

Reference Links

https://www.runoob.com/python/python-email.html

Tags: Programming Python github Mobile

Posted on Thu, 21 May 2020 14:25:40 -0400 by rh-penguin