Gửi thư từ Python bằng SMTP


118

Tôi đang sử dụng phương pháp sau để gửi thư từ Python bằng SMTP. Đó có phải là phương pháp phù hợp để sử dụng hay tôi còn thiếu sót gì không?

from smtplib import SMTP
import datetime

debuglevel = 0

smtp = SMTP()
smtp.set_debuglevel(debuglevel)
smtp.connect('YOUR.MAIL.SERVER', 26)
smtp.login('USERNAME@DOMAIN', 'PASSWORD')

from_addr = "John Doe <john@doe.net>"
to_addr = "foo@bar.com"

subj = "hello"
date = datetime.datetime.now().strftime( "%d/%m/%Y %H:%M" )

message_text = "Hello\nThis is a mail from your server\n\nBye\n"

msg = "From: %s\nTo: %s\nSubject: %s\nDate: %s\n\n%s" 
        % ( from_addr, to_addr, subj, date, message_text )

smtp.sendmail(from_addr, to_addr, msg)
smtp.quit()

2
Đảm bảo rằng bạn lấy đúng Ngày / Giờ. Tôi tìm thấy chức năng sau đây khá hữu ích, cung cấp cho bạn một giá trị hoàn toàn được định dạng cho ngày-Header: docs.python.org/py3k/library/...
BastiBen


đây là một ví dụ mã minh họa cách gửi hình ảnh nội tuyến (cộng với email có cả html và phần văn bản thuần túy) . Nó cũng chỉ ra cách cấu hình các tham số ssl trên các phiên bản Python cũ.
jfs 26/12/13

2
Lưu ý rằng có những thư viện wrapper có sẵn mà làm cho nó ít hơn rất nhiều mã để email gửi (ví dụ như yagmail )
PascalVKooten

Câu trả lời:


111

Kịch bản tôi sử dụng khá giống nhau; Tôi đăng nó ở đây như một ví dụ về cách sử dụng mô-đun email. * Để tạo thông báo MIME; vì vậy script này có thể dễ dàng sửa đổi để đính kèm hình ảnh, v.v.

Tôi dựa vào ISP của mình để thêm tiêu đề ngày giờ.

ISP của tôi yêu cầu tôi sử dụng kết nối smtp an toàn để gửi thư, tôi dựa vào mô-đun smtplib (có thể tải xuống tại http://www1.cs.columbia.edu/~db2501/ssmtplib.py )

Như trong tập lệnh của bạn, tên người dùng và mật khẩu, (các giá trị giả cho sẵn bên dưới), được sử dụng để xác thực trên máy chủ SMTP, ở dạng văn bản thuần túy trong nguồn. Đây là một điểm yếu về bảo mật; nhưng giải pháp thay thế tốt nhất phụ thuộc vào mức độ cẩn thận bạn cần (muốn?) về việc bảo vệ chúng.

=======================================

#! /usr/local/bin/python


SMTPserver = 'smtp.att.yahoo.com'
sender =     'me@my_email_domain.net'
destination = ['recipient@her_email_domain.com']

USERNAME = "USER_NAME_FOR_INTERNET_SERVICE_PROVIDER"
PASSWORD = "PASSWORD_INTERNET_SERVICE_PROVIDER"

# typical values for text_subtype are plain, html, xml
text_subtype = 'plain'


content="""\
Test message
"""

subject="Sent from Python"

import sys
import os
import re

from smtplib import SMTP_SSL as SMTP       # this invokes the secure SMTP protocol (port 465, uses SSL)
# from smtplib import SMTP                  # use this for standard SMTP protocol   (port 25, no encryption)

# old version
# from email.MIMEText import MIMEText
from email.mime.text import MIMEText

try:
    msg = MIMEText(content, text_subtype)
    msg['Subject']=       subject
    msg['From']   = sender # some SMTP servers will do this automatically, not all

    conn = SMTP(SMTPserver)
    conn.set_debuglevel(False)
    conn.login(USERNAME, PASSWORD)
    try:
        conn.sendmail(sender, destination, msg.as_string())
    finally:
        conn.quit()

except:
    sys.exit( "mail failed; %s" % "CUSTOM_ERROR" ) # give an error message

1
@Vincent: thư không thành công; đối tượng 'mô-đun' không có thuộc tính 'SSLFakeSocket' - sử dụng Gmail :(
RadiantHex

Điều này nghe có vẻ giống như một phiên bản hoặc sự cố nhập, để giúp theo dõi nó: Bạn đang chạy phiên bản Python nào? - Bạn có cần kết nối với máy chủ SMTP của mình qua SSL (và nếu có thì bạn nhập ssmtplib, như ở trên)? Bạn có thể nhập trực tiếp smtplib từ python tương tác không, nếu vậy, có lớp smtplib.SSLFakeSocket được định nghĩa không? Hy vọng tôi có thể giúp
Vincent Marchetti

2
Sử dụng smtplib.SMTP_SSL (tiêu chuẩn trong các phiên bản Python mới nhất) để tạo kết nối thay vì ssmtplib.STMP_SSL (mô-đun của bên thứ ba được gợi ý ở trên). Lưu ý rằng mô-đun tiêu chuẩn bắt đầu bằng một 's'. Điều đó đã làm việc cho tôi.
Julio Gorgé

2
thay thế from ssmtplib import SMTP_SSL as SMTPbằng from smtplib import SMTP_SSL as SMTP, và ví dụ này sẽ hoạt động từ thư viện Python chuẩn.
Adam Matan

9
Thêm msg['To'] = ','.join(destination), Nếu không đích không được xem trong gmail
Taha Jahangir

88

Phương pháp tôi thường sử dụng ... không khác nhiều nhưng có một chút

import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText

msg = MIMEMultipart()
msg['From'] = 'me@gmail.com'
msg['To'] = 'you@gmail.com'
msg['Subject'] = 'simple email in python'
message = 'here is the email'
msg.attach(MIMEText(message))

mailserver = smtplib.SMTP('smtp.gmail.com',587)
# identify ourselves to smtp gmail client
mailserver.ehlo()
# secure our email with tls encryption
mailserver.starttls()
# re-identify ourselves as an encrypted connection
mailserver.ehlo()
mailserver.login('me@gmail.com', 'mypassword')

mailserver.sendmail('me@gmail.com','you@gmail.com',msg.as_string())

mailserver.quit()

Đó là nó


Nếu bạn sử dụng Xác minh 2 bước, trước tiên bạn phải tạo mật khẩu dành riêng cho Ứng dụng và thay thế mật khẩu bình thường của bạn bằng mật khẩu đó. Xem Đăng nhập bằng Mật khẩu ứng dụng
Suzana

2
Tôi đồng ý, đây là câu trả lời tốt nhất và nên được chấp nhận. Một trong những thực sự được chấp nhận là thấp hơn.
HelloWorld

6
Đối với python3, hãy sử dụng:from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
art

21

Ngoài ra, nếu bạn muốn thực hiện smtp auth với TLS thay vì SSL thì bạn chỉ cần thay đổi cổng (sử dụng 587) và thực hiện smtp.starttls (). Điều này đã làm việc cho tôi:

...
smtp.connect('YOUR.MAIL.SERVER', 587)
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login('USERNAME@DOMAIN', 'PASSWORD')
...

6

Vấn đề chính mà tôi thấy là bạn không xử lý bất kỳ lỗi nào: .login () và .sendmail () đều có các ngoại lệ được ghi lại mà họ có thể ném ra và có vẻ như .connect () phải có một số cách để chỉ ra rằng nó đã không thể kết nối - có thể là một ngoại lệ do mã ổ cắm bên dưới ném ra.


6

Đảm bảo rằng bạn không có bất kỳ tường lửa nào chặn SMTP. Lần đầu tiên tôi cố gắng gửi một email, nó đã bị cả Windows Firewall và McAfee chặn - mất mãi mãi để tìm thấy cả hai.


6

Cái này thì sao?

import smtplib

SERVER = "localhost"

FROM = "sender@example.com"
TO = ["user@example.com"] # must be a list

SUBJECT = "Hello!"

TEXT = "This message was sent with Python's smtplib."

# Prepare actual message

message = """\
From: %s
To: %s
Subject: %s

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)

# Send the mail

server = smtplib.SMTP(SERVER)
server.sendmail(FROM, TO, message)
server.quit()

4

mã sau đang hoạt động tốt đối với tôi:

import smtplib

to = 'mkyong2002@yahoo.com'
gmail_user = 'mkyong2002@gmail.com'
gmail_pwd = 'yourpassword'
smtpserver = smtplib.SMTP("smtp.gmail.com",587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo() # extra characters to permit edit
smtpserver.login(gmail_user, gmail_pwd)
header = 'To:' + to + '\n' + 'From: ' + gmail_user + '\n' + 'Subject:testing \n'
print header
msg = header + '\n this is test msg from mkyong.com \n\n'
smtpserver.sendmail(gmail_user, to, msg)
print 'done!'
smtpserver.quit()

Tham khảo: http://www.mkyong.com/python/how-do-send-email-in-python-via-smtplib/


1
Flask có một khuôn khổ cho email: from flask.ext.mail import Mail. Tôi đang khắc phục sự cố và nghĩ rằng tôi sẽ quay lại mã Python để xem liệu tôi có thể làm gì đó hoạt động hay không. Tôi thích câu trả lời này vì nó là xương trần. Ồ đúng rồi, và nó đã hoạt động!

Chú ý: Phiên bản trước của câu trả lời có dòng: smtpserver.close()Nó phải là smtpserver.quit():, bởi vì close()sẽ không kết thúc kết nối TLS đúng cách! close()sẽ được gọi trong khi quit().
aronadaal

Xin chào, tôi đang gặp sự cố khi chạy các lệnh trên. khi tôi sử dụng smtpserver.starttls (), tôi nhận được một lỗi SMTP "SMTPServerDisconnected: Kết nối bất ngờ đóng cửa: [Errno 10054]" .. báo cáo trong stackoverflow.com/questions/46094175/...
fazkan


3

Mã ví dụ mà tôi đã làm để gửi thư bằng SMTP.

import smtplib, ssl

smtp_server = "smtp.gmail.com"
port = 587  # For starttls
sender_email = "sender@email"
receiver_email = "receiver@email"
password = "<your password here>"
message = """ Subject: Hi there

This message is sent from Python."""


# Create a secure SSL context
context = ssl.create_default_context()

# Try to log in to server and send email
server = smtplib.SMTP(smtp_server,port)

try:
    server.ehlo() # Can be omitted
    server.starttls(context=context) # Secure the connection
    server.ehlo() # Can be omitted
    server.login(sender_email, password)
    server.sendmail(sender_email, receiver_email, message)
except Exception as e:
    # Print any error messages to stdout
    print(e)
finally:
    server.quit()

2

Xem tất cả những câu trả lời dài? Hãy cho phép tôi tự quảng cáo bằng cách làm tất cả trong một vài dòng.

Nhập và kết nối:

import yagmail
yag = yagmail.SMTP('john@doe.net', host = 'YOUR.MAIL.SERVER', port = 26)

Sau đó, nó chỉ là một lớp lót:

yag.send('foo@bar.com', 'hello', 'Hello\nThis is a mail from your server\n\nBye\n')

Nó thực sự sẽ đóng khi vượt ra khỏi phạm vi (hoặc có thể được đóng theo cách thủ công). Hơn nữa, nó sẽ cho phép bạn đăng ký tên người dùng của mình trong keyring để bạn không phải viết mật khẩu trong script của mình (nó thực sự làm phiền tôi trước khi viết yagmail!)

Đối với gói / cài đặt, các mẹo và thủ thuật, vui lòng xem git hoặc pip , có sẵn cho cả Python 2 và 3.


@PascalvKoolen Tôi đã cài đặt yagmail và thử kết nối bằng cách cung cấp id email và mật khẩu của mình. nhưng nó đã cho tôi một lỗi xác thực
fazkan

0

bạn có thể làm như vậy

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


server = smtplib.SMTP('mail.servername.com', 25)
server.ehlo()
server.starttls()

server.login('username', 'password')
from = 'me@servername.com'
to = 'mygfriend@servername.com'
body = 'That A Message For My Girl Friend For tell Him If We will go to eat Something This Nigth'
subject = 'Invite to A Diner'
msg = MIMEText(body,'plain','utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = Header(from, 'utf-8')
msg['To'] = Header(to, 'utf-8')
message = msg.as_string()
server.sendmail(from, to, message)

0

Đây là một ví dụ làm việc cho Python 3.x

#!/usr/bin/env python3

from email.message import EmailMessage
from getpass import getpass
from smtplib import SMTP_SSL
from sys import exit

smtp_server = 'smtp.gmail.com'
username = 'your_email_address@gmail.com'
password = getpass('Enter Gmail password: ')

sender = 'your_email_address@gmail.com'
destination = 'recipient_email_address@gmail.com'
subject = 'Sent from Python 3.x'
content = 'Hello! This was sent to you via Python 3.x!'

# Create a text/plain message
msg = EmailMessage()
msg.set_content(content)

msg['Subject'] = subject
msg['From'] = sender
msg['To'] = destination

try:
    s = SMTP_SSL(smtp_server)
    s.login(username, password)
    try:
        s.send_message(msg)
    finally:
        s.quit()

except Exception as E:
    exit('Mail failed: {}'.format(str(E)))

0

Dựa trên ví dụ này, tôi đã thực hiện chức năng sau:

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

def send_email(host, port, user, pwd, recipients, subject, body, html=None, from_=None):
    """ copied and adapted from
        /programming/10147455/how-to-send-an-email-with-gmail-as-provider-using-python#12424439
    returns None if all ok, but if problem then returns exception object
    """

    PORT_LIST = (25, 587, 465)

    FROM = from_ if from_ else user 
    TO = recipients if isinstance(recipients, (list, tuple)) else [recipients]
    SUBJECT = subject
    TEXT = body.encode("utf8") if isinstance(body, unicode) else body
    HTML = html.encode("utf8") if isinstance(html, unicode) else html

    if not html:
        # Prepare actual message
        message = """From: %s\nTo: %s\nSubject: %s\n\n%s
        """ % (FROM, ", ".join(TO), SUBJECT, TEXT)
    else:
                # /programming/882712/sending-html-email-using-python#882770
        msg = MIMEMultipart('alternative')
        msg['Subject'] = SUBJECT
        msg['From'] = FROM
        msg['To'] = ", ".join(TO)

        # Record the MIME types of both parts - text/plain and text/html.
        # utf-8 -> /programming/5910104/python-how-to-send-utf-8-e-mail#5910530
        part1 = MIMEText(TEXT, 'plain', "utf-8")
        part2 = MIMEText(HTML, 'html', "utf-8")

        # 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)

        message = msg.as_string()


    try:
        if port not in PORT_LIST: 
            raise Exception("Port %s not one of %s" % (port, PORT_LIST))

        if port in (465,):
            server = smtplib.SMTP_SSL(host, port)
        else:
            server = smtplib.SMTP(host, port)

        # optional
        server.ehlo()

        if port in (587,): 
            server.starttls()

        server.login(user, pwd)
        server.sendmail(FROM, TO, message)
        server.close()
        # logger.info("SENT_EMAIL to %s: %s" % (recipients, subject))
    except Exception, ex:
        return ex

    return None

nếu bạn chỉ chuyển bodythì thư văn bản thuần túy sẽ được gửi đi, nhưng nếu bạn chuyển htmlđối số cùng với bodyđối số, thì email html sẽ được gửi (với nội dung văn bản dự phòng cho các ứng dụng email không hỗ trợ loại html / mime).

Ví dụ sử dụng:

ex = send_email(
      host        = 'smtp.gmail.com'
   #, port        = 465 # OK
    , port        = 587  #OK
    , user        = "xxx@gmail.com"
    , pwd         = "xxx"
    , from_       = 'xxx@gmail.com'
    , recipients  = ['yyy@gmail.com']
    , subject     = "Test from python"
    , body        = "Test from python - body"
    )
if ex: 
    print("Mail sending failed: %s" % ex)
else:
    print("OK - mail sent"

Btw. Nếu bạn muốn sử dụng gmail làm máy chủ SMTP thử nghiệm hoặc sản xuất, hãy bật quyền truy cập tạm thời hoặc vĩnh viễn vào các ứng dụng kém bảo mật hơn:

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.