email: Ví dụ¶
Dưới đây là một số ví dụ về cách sử dụng gói email để đọc, viết và gửi các tin nhắn email đơn giản cũng như các tin nhắn MIME phức tạp hơn.
Trước tiên, hãy xem cách tạo và gửi một tin nhắn văn bản đơn giản (cả nội dung văn bản và địa chỉ có thể chứa các ký tự unicode):
# Import smtplib cho chức năng gửi thực tế
nhập smtplib
# Import các mô-đun email chúng tôi sẽ cần
từ nhập email.message EmailMessage
# Open tệp văn bản thuần túy có tên trong tệp văn bản để đọc.
với open(textfile) là fp:
# Create một tin nhắn văn bản/tin nhắn đơn giản
tin nhắn = EmailMessage()
msg.set_content(fp.read())
# me == địa chỉ email của người gửi
# you == địa chỉ email của người nhận
msg['Subject'] = f'Nội dung của {textfile}'
tin nhắn['Từ'] = tôi
tin nhắn['To'] = bạn
# Send tin nhắn qua máy chủ SMTP của chúng tôi.
s = smtplib.SMTP('localhost')
s.send_message(tin nhắn)
s.quit()
Việc phân tích cú pháp các tiêu đề RFC 822 có thể dễ dàng được thực hiện bằng cách sử dụng các lớp từ mô-đun parser:
# Import các mô-đun email chúng tôi sẽ cần
#from email.parser nhập BytesParser
từ email.parser nhập Trình phân tích cú pháp
từ mặc định nhập email.policy
# If các tiêu đề e-mail nằm trong một tệp, bỏ ghi chú hai dòng sau:
# with open(messagefile, 'rb') as fp:
# headers = BytesParser(policy=default).parse(fp)
# Or để phân tích các tiêu đề trong chuỗi (đây là thao tác không phổ biến), hãy sử dụng:
tiêu đề = Trình phân tích cú pháp(chính sách=mặc định).parsestr(
'Từ: Foo Bar <user@example.com>\n'
'Tới: <someone_else@example.com>\n'
'Chủ đề: Kiểm tra tin nhắn\n'
'\n'
'Thân thể sẽ đi tới đây\n')
# Now các mục tiêu đề có thể được truy cập dưới dạng từ điển:
print('To: {}'.format(headers['to']))
print('Từ: {}'.format(headers['from']))
print('Chủ đề: {}'.format(headers['subject']))
# You cũng có thể truy cập các phần của địa chỉ:
print('Tên người dùng của người nhận: {}'.format(headers['to'].addresses[0].username))
print('Tên người gửi: {}'.format(headers['from'].addresses[0].display_name))
Dưới đây là ví dụ về cách gửi tin nhắn MIME chứa nhiều ảnh gia đình có thể nằm trong một thư mục:
# Import smtplib cho chức năng gửi thực tế.
nhập smtplib
# Here là các mô-đun gói email mà chúng tôi cần.
từ nhập email.message EmailMessage
# Create thư email chứa.
tin nhắn = EmailMessage()
msg['Subject'] = 'Gia đình chúng ta đoàn tụ'
# me == địa chỉ email của người gửi
# family = danh sách địa chỉ email của tất cả người nhận
tin nhắn['Từ'] = tôi
msg['To'] = ', '.join(family)
msg.preamble = 'Bạn sẽ không thấy điều này trong trình đọc thư nhận biết MIME.\n'
# Open các tập tin ở chế độ nhị phân. Bạn cũng có thể bỏ qua kiểu phụ
# if bạn muốn MIMEImage đoán nó.
cho tập tin trong pngfiles:
với open(file, 'rb') là fp:
img_data = fp.read()
msg.add_attachment(img_data, maintype='hình ảnh',
loại phụ='png')
# Send email qua máy chủ SMTP của chúng tôi.
với smtplib.SMTP('localhost') là s:
s.send_message(tin nhắn)
Đây là ví dụ về cách gửi toàn bộ nội dung của một thư mục dưới dạng email: [1]
#!/usr/bin/env python3
"""Gửi nội dung của một thư mục dưới dạng tin nhắn MIME."""
hệ điều hành nhập khẩu
nhập smtplib
# For đoán loại MIME dựa trên phần mở rộng tên tệp
nhập mô phỏng
từ nhập khẩu argparse ArgumentParser
từ nhập email.message EmailMessage
từ email.policy nhập SMTP
chắc chắn chính():
trình phân tích cú pháp = ArgumentParser(description="""\
Gửi nội dung của một thư mục dưới dạng tin nhắn MIME.
Trừ khi tùy chọn -o được cung cấp, email sẽ được gửi bằng cách chuyển tiếp đến địa phương của bạn
máy chủ SMTP, sau đó thực hiện quá trình phân phối bình thường. Máy cục bộ của bạn
phải đang chạy máy chủ SMTP.
""")
parser.add_argument('-d', '--directory',
help="""Gửi nội dung của thư mục được chỉ định,
nếu không thì sử dụng thư mục hiện tại. Chỉ thường xuyên
các tập tin trong thư mục được gửi đi và chúng tôi không lặp lại
thư mục con.""")
parser.add_argument('-o', '--output',
metavar='FILE',
help="""In tin nhắn đã soạn tới FILE thay vì
gửi tin nhắn đến máy chủ SMTP.""")
parser.add_argument('-s', '--sender', require=True,
help='Giá trị của tiêu đề From: (bắt buộc)')
parser.add_argument('-r', '--recipient', require=True,
hành động='nối thêm', metavar='RECIPIENT',
default=[], dest='người nhận',
help='A To: giá trị tiêu đề (bắt buộc ít nhất một giá trị)')
args = trình phân tích cú pháp.parse_args()
thư mục = args.directory
nếu không phải thư mục:
thư mục = '.'
# Create tin nhắn
tin nhắn = EmailMessage()
msg['Subject'] = f'Nội dung của thư mục {os.path.abspath(directory)}'
msg['To'] = ', '.join(args.recipients)
msg['From'] = args.sender
msg.preamble = 'Bạn sẽ không thấy điều này trong trình đọc thư nhận biết MIME.\n'
cho tên tệp trong os.listdir (thư mục):
path = os.path.join(thư mục, tên tệp)
nếu không phải os.path.isfile(path):
tiếp tục
# Guess loại nội dung dựa trên phần mở rộng của tệp. Mã hóa
# will bị bỏ qua, mặc dù chúng ta nên kiểm tra những thứ đơn giản như
# gzip'd hoặc các tập tin nén.
ctype, mã hóa = mimetypes.guess_file_type(path)
nếu ctype là Không hoặc mã hóa không phải là Không:
# No có thể được đoán hoặc tệp được mã hóa (nén), vì vậy
# use một loại túi bit chung.
ctype = 'ứng dụng/octet-stream'
kiểu chính, kiểu phụ = ctype.split('/', 1)
với open(path, 'rb') là fp:
tin nhắn.add_attachment(fp.read(),
maintype=loại chính,
loại phụ=loại phụ,
tên tệp=tên tệp)
# Now gửi hoặc lưu trữ tin nhắn
nếu args.output:
với open(args.output, 'wb') là fp:
fp.write(msg.as_bytes(policy=SMTP))
khác:
với smtplib.SMTP('localhost') là s:
s.send_message(tin nhắn)
nếu __name__ == '__main__':
chính()
Dưới đây là ví dụ về cách giải nén tin nhắn MIME giống như tin nhắn ở trên vào một thư mục chứa các tệp:
#!/usr/bin/env python3
"""Giải nén tin nhắn MIME vào một thư mục chứa các tập tin."""
hệ điều hành nhập khẩu
nhập email
nhập mô phỏng
từ mặc định nhập email.policy
từ nhập khẩu argparse ArgumentParser
chắc chắn chính():
trình phân tích cú pháp = ArgumentParser(description="""\
Giải nén tin nhắn MIME vào một thư mục chứa các tập tin.
""")
parser.add_argument('-d', '--directory', require=True,
help="""Giải nén tin nhắn MIME vào tên
thư mục sẽ được tạo nếu chưa có
tồn tại.""")
parser.add_argument('msgfile')
args = trình phân tích cú pháp.parse_args()
với open(args.msgfile, 'rb') là fp:
msg = email.message_from_binary_file(fp, Policy=default)
thử:
os.mkdir(args.directory)
ngoại trừ FileExistsError:
vượt qua
bộ đếm = 1
một phần trong msg.walk():
# multipart/* chỉ là vùng chứa
nếu part.get_content_maintype() == 'multipart':
tiếp tục
# Applications thực sự nên làm sạch tên tệp đã cho để
Không thể sử dụng tin nhắn # email để ghi đè các tệp quan trọng
tên tệp = part.get_filename()
nếu không phải tên tệp:
ext = mimetypes.guess_extension(part.get_content_type())
nếu không phải là máy lẻ:
# Use một tiện ích mở rộng túi bit chung
ext = '.bin'
tên tệp = f'part-{counter:03d}{ext}'
bộ đếm += 1
với open(os.path.join(args.directory, filename), 'wb') là fp:
fp.write(part.get_payload(decode=True))
nếu __name__ == '__main__':
chính()
Đây là ví dụ về cách tạo tin nhắn HTML bằng phiên bản văn bản thuần túy thay thế. Để làm cho mọi thứ thú vị hơn một chút, chúng tôi đưa hình ảnh liên quan vào phần html và lưu bản sao của những gì chúng tôi sẽ gửi vào đĩa cũng như gửi nó.
#!/usr/bin/env python3
nhập smtplib
từ nhập email.message EmailMessage
từ email.headerregistry nhập Địa chỉ
từ email.utils nhập make_msgid
# Create tin nhắn văn bản cơ bản.
tin nhắn = EmailMessage()
msg['Subject'] = "Pourquoi pas des asperges pour ce midi ?"
msg['From'] = Địa chỉ("Pepé Le Pew", "pepe", "example.com")
msg['To'] = (Địa chỉ("Penelope Pussycat", "penelope", "example.com"),
Địa chỉ("Fabrette Pussycat", "fabrette", "example.com"))
msg.set_content("""\
Chào!
Cette recette [1] sera sûrement un très bon repas.
[1] http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718
--Pepé
""")
# Add phiên bản html. Điều này chuyển đổi tin nhắn thành nhiều phần/thay thế
# container, với tin nhắn văn bản gốc là phần đầu tiên và html mới
# message là phần thứ hai.
măng tây_cid = make_msgid()
msg.add_alternative("""\
<html>
<đầu></head>
<cơ thể>
<p>Xin chào!</p>
<p>Cette
<a href="http://www.yummly.com/recipe/Roasted-Asparagus-Epicurious-203718">
hộp đựng nước
</a> sera sûrement un très bon repas.
</p>
<img src="cid:{asparagus_cid}">
</body>
</html>
""".format(asparagus_cid=asparagus_cid[1:-1]), subtype='html')
# note rằng chúng tôi cần loại bỏ <> khỏi msgid để sử dụng trong html.
# Now thêm hình ảnh liên quan vào phần html.
với open("rang-asparagus.jpg", 'rb') là img:
msg.get_payload()[1].add_similar(img.read(), 'image', 'jpeg',
cid=măng tây_cid)
# Make một bản sao cục bộ của những gì chúng tôi sẽ gửi.
với open('outending.msg', 'wb') là f:
f.write(byte(tin nhắn))
# Send tin nhắn qua máy chủ SMTP cục bộ.
với smtplib.SMTP('localhost') là s:
s.send_message(tin nhắn)
Nếu chúng tôi nhận được tin nhắn từ ví dụ trước, đây là một cách chúng tôi có thể xử lý nó:
hệ điều hành nhập khẩu
hệ thống nhập khẩu
nhập tệp tạm thời
nhập mô phỏng
nhập trình duyệt web
# Import các mô-đun email chúng tôi sẽ cần
từ chính sách nhập email
từ email.parser nhập BytesParser
def magic_html_parser(html_text, partfiles):
"""Trả về html đã được vệ sinh an toàn được liên kết với các tệp phần.
Viết lại các thuộc tính href="cid:...." để trỏ đến tên tệp trong partfiles.
Mặc dù không tầm thường nhưng điều này có thể thực hiện được bằng cách sử dụng html.parser.
"""
raise NotImplementedError("Thêm phép thuật cần thiết")
# In một chương trình thực sự mà bạn sẽ lấy tên tệp từ các đối số.
với open('outending.msg', 'rb') là fp:
msg = BytesParser(policy=policy.default).parse(fp)
# Now các mục tiêu đề có thể được truy cập dưới dạng từ điển và mọi mục không phải ASCII sẽ
# be được chuyển đổi sang unicode:
print('To:', msg['to'])
print('Từ:', msg['from'])
print('Chủ đề:', msg['chủ đề'])
# If chúng tôi muốn in bản xem trước nội dung tin nhắn, chúng tôi có thể trích xuất bất cứ thứ gì
# the tải trọng được định dạng ít nhất và in ba dòng đầu tiên. Tất nhiên,
# if tin nhắn không có phần văn bản đơn giản in ba dòng html đầu tiên
# is có lẽ vô dụng, nhưng đây chỉ là một ví dụ mang tính khái niệm.
đơn giản nhất = msg.get_body(preferencelist=('plain', 'html'))
in()
print(''.join(simplest.get_content().splitlines(keepends=True)[:3]))
ans = input("Xem toàn bộ tin nhắn?")
nếu ans.low()[0] == 'n':
sys.exit()
# We có thể trích xuất giải pháp thay thế phong phú nhất để hiển thị nó:
giàu nhất = msg.get_body()
tập tin một phần = {}
if giàu nhất['content-type'].maintype == 'text':
nếu giàu nhất['content-type'].subtype == 'plain':
cho dòng trong rich.get_content().splitlines():
in (dòng)
sys.exit()
elif giàu nhất['content-type'].subtype == 'html':
cơ thể = giàu có nhất
khác:
print("Không biết cách hiển thị {}".format(richest.get_content_type()))
sys.exit()
elif giàu nhất['content-type'].content_type == 'nhiều phần/có liên quan':
body = rich.get_body(preferencelist=('html'))
một phần trong rich.iter_attachments():
fn = part.get_filename()
nếu fn:
phần mở rộng = os.path.splitext(part.get_filename())[1]
khác:
tiện ích mở rộng = mimetypes.guess_extension(part.get_content_type())
với tempfile.NamedTemporaryFile(suffix=extension, delete=False) là f:
f.write(part.get_content())
# again loại bỏ <> để chuyển từ dạng email dạng cid sang dạng html.
partfiles[part['content-id'][1:-1]] = f.name
khác:
print("Không biết cách hiển thị {}".format(richest.get_content_type()))
sys.exit()
với tempfile.NamedTemporaryFile(mode='w', delete=False) là f:
f.write(magic_html_parser(body.get_content(), partfiles))
webbrowser.open(f.name)
os.remove(f.name)
cho fn trong partfiles.values():
os.remove(fn)
Tất nhiên, # Of, có rất nhiều email có thể phá vỡ sự đơn giản này
# minded, nhưng nó sẽ xử lý những chương trình phổ biến nhất.
Theo lời nhắc, đầu ra từ trên là:
Tới: Penelope Pussycat <penelope@example.com>, Fabrette Pussycat <fabrette@example.com>
Từ: Pepé Le Pew <pepe@example.com>
Chủ đề: Pourquoi pas des asperges pour ce midi ?
Chào!
Cette recette [1] sera sûrement un très bon repas.
Chú thích cuối trang