使用Python发送带附件的邮件

时间:2017-11-01 11:37:57

标签: python-3.x smtp mime

我是python的新手。以下是我们用于发送邮件的代码。

import smtplib
import shutil
import os
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders

To="maniram.220@gmailcom"
Subject="mail through code"
Text="Hai!"
mail_sender="pull@gmail.com"
mail_passwd="ZSDCXFF"

server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.ehlo
server.login(mail_sender,mail_passwd)
BODY='\r\n' .join(['To: %s' % To,'From: %s' % mail_sender,'Subject: %s' % Subject,'',Text])
try:
    server.sendmail(mail_sender,[To],BODY)
    print("email sent")
except:
    print("error sending email")
    server.quit()

我需要压缩文件夹中的文件(用户指定的路径),然后将其作为附件邮寄 我怎样才能达到这个目标?

1 个答案:

答案 0 :(得分:0)

以下显示可能没有必要压缩整个目录以将其附加到电子邮件中。相反,只需根据需要调整FILE_PATHS变量即可考虑所有文件。或者,您可以自由使用create_attachment自动识别目录,将其压缩,并创建一个名称相同的附件以包含在电子邮件中。

#! /usr/bin/env python3
import collections
import contextlib
import email.encoders
import email.mime.application
import email.mime.audio
import email.mime.base
import email.mime.image
# import email.mime.message
import email.mime.multipart
import email.mime.text
import email.utils
import getpass
import mimetypes
import pathlib
import smtplib
import string
import tempfile
import uuid
import zipfile

FROM = 'John Doe', 'john.doe@gmail.com'
SUBJECT = 'Email Demonstration'
TO = [
    ('Jane Doe', 'jane.doe@gmail.com'),
    ('Mary Doe', 'mary.doe@gmail.com')
]
FILE_PATHS = [
    pathlib.Path(r'C:\path\to\my\file'),
    pathlib.Path(r'C:\path\to\another\file'),
    pathlib.Path(r'C:\path to\yet\another\file'),
    pathlib.Path(r'C:\why\are\there\so\many\paths')
]
PLAIN_MESSAGE = '''\
Hello, Jane and Mary!
How are you doing?
Hope you like the email.'''
HTML_TEMPLATE = r'''<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="${content_type}">
    <title>${title}</title>
    <style type="text/css" media="all">
        .key {
            color: #0066AA;
            font-family: sans-serif;
            font-size: 14px;
            font-weight: bold;
        }
        .value {
            color: #000000;
            font-family: monospace;
            font-size: 12px;
            font-weight: normal;
        }
    </style>
</head>
<body>
<div class="value">
    <span class="key">${header}</span>
${message}
</div>
<div class="value">
    <span class="key">File Manifest</span>
${manifest}
</div>
</body>
</html>'''
HTML_MESSAGE = [
    'When will the event start, and how much time do ushers need to show up '
    'before the event?',
    'Who will be admitted to the event, will they require tickets, and what '
    'is to be done if we run out of room?',
    'Where will the event be taking place, and will ushers need to enter '
    'through a different way than everyone else?',
    'How do you want your ushers to act, and will you have a rehearsal or '
    'practice session explaining your expectations?',
    'What clothing do you want ushers to where; and do you want the standard '
    'black suit, white shirt, and red tie ushers usually where around here?'
]


def main():
    message = create_multipart()
    for path in FILE_PATHS:
        mime, handle = create_attachment(path)
        message.attach(mime)
    message.attach(email.mime.text.MIMEText(PLAIN_MESSAGE, 'plain'))
    attach_html_text(message)
    with smtplib.SMTP('smtp.gmail.com', 587) as server:
        server.starttls()
        server.login(input('Username: '), getpass.getpass())
        server.send_message(message)


def create_multipart():
    message = email.mime.multipart.MIMEMultipart('alternative')
    message['Message-ID'] = make_message_id()
    message['From'] = email.utils.formataddr(FROM)
    message['Date'] = email.utils.formatdate(localtime=True)
    message['Subject'] = SUBJECT
    message['To'] = email.utils.COMMASPACE.join(map(
        email.utils.formataddr, TO
    ))
    return message


def make_message_id():
    return email.utils.make_msgid(str(uuid.uuid4()))


@contextlib.contextmanager
def create_temp_zip_file(directory):
    paths_to_zip = collections.deque([directory])
    with tempfile.TemporaryDirectory() as root:
        handle = pathlib.Path(root) / f'{directory.name}.zip'
        with zipfile.ZipFile(handle, 'x') as file:
            while paths_to_zip:
                path = paths_to_zip.popleft()
                if path.is_dir():
                    paths_to_zip.extend(path.iterdir())
                elif path.is_file():
                    file.write(path, path.relative_to(directory))
        yield handle


def create_attachment(path):
    if path.is_dir():
        with create_temp_zip_file(path) as handle:
            return create_attachment(handle)
    kind, encoding = mimetypes.guess_type(str(path))
    if kind is None:
        kind = 'application/octet-stream'
    main_type, sub_type = kind.split('/')
    if main_type == 'application':
        with path.open('rb') as file:
            mime = email.mime.application.MIMEApplication(
                file.read(),
                sub_type
            )
    elif main_type == 'audio':
        with path.open('rb') as file:
            audio_data = file.read()
        try:
            mime = email.mime.audio.MIMEAudio(audio_data)
        except TypeError:
            mime = email.mime.audio.MIMEAudio(audio_data, sub_type)
    elif main_type == 'image':
        with path.open('rb') as file:
            image_data = file.read()
        try:
            mime = email.mime.image.MIMEImage(image_data)
        except TypeError:
            mime = email.mime.image.MIMEImage(image_data, sub_type)
    # elif main_type == 'message':
    #     attachment = email.mime.message.MIMEMessage()
    elif main_type == 'text':
        with path.open('rt') as file:
            mime = email.mime.text.MIMEText(file.read(), sub_type)
    else:
        mime = email.mime.base.MIMEBase(main_type, sub_type)
        with path.open('rb') as file:
            mime.set_payload(file.read())
        email.encoders.encode_base64(mime)
    mime.add_header('Content-Disposition', 'attachment', filename=path.name)
    content_id = make_message_id()
    mime.add_header('Content-ID', content_id)
    handle = f'"cid:{content_id.strip("<>")}"'
    return mime, handle


def attach_html_text(message):
    mapping = dict(
        content_type='',
        title=message['Subject'],
        header=message['Subject'],
        message=make_html_list(HTML_MESSAGE, 'o', 1),
        manifest=make_html_list(FILE_PATHS, 'u', 1)
    )
    template = string.Template(HTML_TEMPLATE)
    mime = email.mime.text.MIMEText(template.substitute(mapping), 'html')
    mapping['content_type'] = mime['Content-Type'].replace('"', '')
    mime = email.mime.text.MIMEText(template.substitute(mapping), 'html')
    message.attach(mime)


def make_html_list(iterable, kind, indent=0, space=' ' * 4):
    prefix = space * indent
    elements = [f'{prefix}<{kind}l>']
    elements.extend(f'{prefix}{space}<li>{item}</li>' for item in iterable)
    elements.append(f'{prefix}</{kind}l>')
    return '\n'.join(elements)


if __name__ == '__main__':
    main()