การส่งเมลจาก Python โดยใช้ SMTP


118

ฉันใช้วิธีต่อไปนี้เพื่อส่งอีเมลจาก Python โดยใช้ SMTP เป็นวิธีการที่ถูกต้องหรือมี gotchas ที่ฉันหายไป?

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
ตรวจสอบให้แน่ใจว่าคุณได้รับวันที่ / เวลาที่ถูกต้อง ฉันพบว่าฟังก์ชันต่อไปนี้มีประโยชน์มากซึ่งให้ค่าที่จัดรูปแบบอย่างสมบูรณ์แบบสำหรับ Date-Header: docs.python.org/py3k/library/…
BastiBen


นี่เป็นตัวอย่างโค้ดที่แสดงให้เห็นถึงวิธีการที่จะส่งภาพแบบอินไลน์ (บวกอีเมลที่มีทั้ง HTML และชิ้นส่วนข้อความธรรมดา) นอกจากนี้ยังแสดงวิธีกำหนดค่าพารามิเตอร์ ssl ใน Python เวอร์ชันเก่า
jfs

2
โปรดทราบว่ามีไลบรารีของ wrapper ซึ่งทำให้รหัสในการส่งอีเมลน้อยลงมาก (เช่นyagmail )
PascalVKooten

คำตอบ:


111

สคริปต์ที่ฉันใช้ค่อนข้างคล้ายกัน ฉันโพสต์ไว้ที่นี่เพื่อเป็นตัวอย่างวิธีการใช้โมดูลอีเมล * เพื่อสร้างข้อความ MIME เพื่อให้สามารถแก้ไขสคริปต์นี้เพื่อแนบรูปภาพ ฯลฯ ได้อย่างง่ายดาย

ฉันพึ่งพา ISP ของฉันเพื่อเพิ่มส่วนหัววันเวลา

ISP ของฉันต้องการให้ฉันใช้การเชื่อมต่อ smtp ที่ปลอดภัยในการส่งอีเมลฉันอาศัยโมดูล smtplib (ดาวน์โหลดได้ที่http://www1.cs.columbia.edu/~db2501/ssmtplib.py )

เช่นเดียวกับในสคริปต์ของคุณชื่อผู้ใช้และรหัสผ่าน (กำหนดค่าดัมมี่ด้านล่าง) ที่ใช้ในการตรวจสอบสิทธิ์บนเซิร์ฟเวอร์ SMTP จะเป็นข้อความธรรมดาในแหล่งที่มา นี่คือจุดอ่อนด้านความปลอดภัย แต่ทางเลือกที่ดีที่สุดขึ้นอยู่กับว่าคุณต้องระมัดระวังแค่ไหนในการปกป้องสิ่งเหล่านี้

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

#! /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: mail ล้มเหลว; วัตถุ "module" ไม่มีแอตทริบิวต์ "SSLFakeSocket" - ใช้ Gmail :(
RadiantHex

ดูเหมือนจะเป็นปัญหาเกี่ยวกับเวอร์ชันหรือการนำเข้าเพื่อช่วยในการติดตาม: คุณใช้ Python เวอร์ชันใดอยู่ - คุณจำเป็นต้องเชื่อมต่อกับเซิร์ฟเวอร์ SMTP ของคุณผ่าน SSL หรือไม่ (และหากเป็นเช่นนั้นคุณจะนำเข้า ssmtplib ดังที่กล่าวมา) คุณสามารถนำเข้า smtplib โดยตรงจาก python โต้ตอบได้หรือไม่ถ้าเป็นเช่นนั้นมีการกำหนดคลาส smtplib.SSLFakeSocket หรือไม่ หวังว่าฉันจะช่วยได้
Vincent Marchetti

2
ใช้ smtplib.SMTP_SSL (มาตรฐานใน Python เวอร์ชันล่าสุด) เพื่อสร้างการเชื่อมต่อแทน ssmtplib.STMP_SSL (โมดูลของบุคคลที่สามระบุไว้ด้านบน) สังเกตว่าโมดูลมาตรฐานขึ้นต้นด้วย 's' ที่ได้ผลสำหรับฉัน
Julio Gorgé

2
แทนที่from ssmtplib import SMTP_SSL as SMTPด้วยfrom smtplib import SMTP_SSL as SMTPและตัวอย่างนี้จะทำงานจากไลบรารี Python มาตรฐาน
Adam Matan

9
เพิ่มmsg['To'] = ','.join(destination)ไม่งั้นดูปลายทางใน gmail
Taha Jahangir

88

วิธีที่ฉันใช้กันทั่วไป ... ไม่แตกต่างกันมาก แต่เล็กน้อย

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

แค่นั้นแหละ


หากคุณใช้การยืนยันแบบ 2 ขั้นตอนคุณต้องสร้างรหัสผ่านเฉพาะแอปก่อนและแทนที่รหัสผ่านปกติของคุณด้วยรหัสผ่าน ดูการลงชื่อเข้าใช้โดยใช้รหัสผ่านสำหรับแอป
Suzana

2
ฉันเห็นด้วยนี่คือคำตอบที่ดีที่สุดและควรยอมรับ คนที่ได้รับการยอมรับว่าด้อยกว่าจริงๆ
HelloWorld

6
สำหรับ python3 ให้ใช้:from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
ศิลปะ

21

นอกจากนี้หากคุณต้องการทำ smtp auth ด้วย TLS ซึ่งตรงข้ามกับ SSL คุณก็ต้องเปลี่ยนพอร์ต (ใช้ 587) และทำ smtp.starttls () สิ่งนี้ใช้ได้ผลสำหรับฉัน:

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

6

gotcha หลักที่ฉันเห็นคือคุณไม่ได้จัดการข้อผิดพลาดใด ๆ : .login () และ. sendmail () ทั้งคู่มีเอกสารข้อยกเว้นที่พวกเขาสามารถโยนได้และดูเหมือนว่า .connect () ต้องมีวิธีระบุว่าเป็น ไม่สามารถเชื่อมต่อ - อาจเป็นข้อยกเว้นที่เกิดจากรหัสซ็อกเก็ตที่อยู่เบื้องหลัง


6

ตรวจสอบให้แน่ใจว่าคุณไม่มีไฟร์วอลล์ใด ๆ ที่บล็อก SMTP ครั้งแรกที่ฉันพยายามส่งอีเมลมันถูกบล็อกทั้งโดย Windows Firewall และ McAfee - ใช้เวลาตลอดไปในการค้นหาทั้งคู่


6

อะไรประมาณนี้

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

รหัสต่อไปนี้ใช้งานได้ดีสำหรับฉัน:

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

อ้างอิง: http://www.mkyong.com/python/how-do-send-email-in-python-via-smtplib/


1
Flask มีกรอบสำหรับอีเมล: from flask.ext.mail import Mail ฉันกำลังแก้ไขปัญหาและคิดว่าฉันจะกลับไปที่โค้ด Python เพื่อดูว่าฉันจะได้รับบางสิ่งที่ใช้งานได้หรือไม่ ฉันชอบคำตอบนี้เพราะมันเป็นกระดูกเปล่า โอ้ใช่และได้ผล!

ข้อควรสนใจ:คำตอบเวอร์ชันก่อนหน้านี้มีบรรทัด: smtpserver.close()ต้องเป็น: smtpserver.quit()เนื่องจากclose()จะไม่ยุติการเชื่อมต่อ TLS อย่างถูกต้อง! จะถูกเรียกว่าในช่วงclose() quit()
aronadaal

สวัสดีฉันมีปัญหาในการรันสัญญาณเหนือคำสั่ง เมื่อฉันใช้ smtpserver.starttls () ฉันได้รับข้อผิดพลาด SMTP "SMTPServerDisconnected: การเชื่อมต่อปิดโดยไม่คาดคิด: [Errno 10054]" .. รายงานใน stackoverflow.com/questions/46094175/…
fazkan


3

รหัสตัวอย่างที่ฉันทำเพื่อส่งเมลโดยใช้ 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

ดูคำตอบที่ยาวทั้งหมดนี้หรือไม่? โปรดให้ฉันโปรโมตตัวเองโดยทำทุกอย่างในสองสามบรรทัด

นำเข้าและเชื่อมต่อ:

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

จากนั้นเป็นเพียงซับเดียว:

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

มันจะปิดจริงๆเมื่ออยู่นอกขอบเขต (หรือปิดเองก็ได้) นอกจากนี้ยังช่วยให้คุณสามารถลงทะเบียนชื่อผู้ใช้ของคุณในพวงกุญแจของคุณโดยที่คุณไม่ต้องเขียนรหัสผ่านในสคริปต์ของคุณ (มันรบกวนฉันมากก่อนที่จะเขียนyagmail!)

สำหรับแพ็คเกจ / การติดตั้งคำแนะนำและเคล็ดลับโปรดดูที่gitหรือpipซึ่งมีให้สำหรับทั้ง Python 2 และ 3


@PascalvKoolen ฉันติดตั้ง yagmail และพยายามเชื่อมต่อโดยให้รหัสอีเมลและรหัสผ่านของฉัน แต่มันทำให้ฉันมีข้อผิดพลาดในการตรวจสอบสิทธิ์
fazkan

0

คุณสามารถทำเช่นนั้นได้

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

นี่คือตัวอย่างการทำงานของ 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

จากตัวอย่างนี้ฉันทำฟังก์ชันต่อไปนี้:

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

หากคุณส่งผ่านเท่านั้นbodyข้อความธรรมดาจะถูกส่ง แต่ถ้าคุณส่งผ่านhtmlอาร์กิวเมนต์พร้อมกับbodyอาร์กิวเมนต์อีเมล html จะถูกส่งไป (โดยมีเนื้อหาแบบข้อความสำรองสำหรับไคลเอนต์อีเมลที่ไม่รองรับประเภท html / mime)

ตัวอย่างการใช้งาน:

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 หากคุณต้องการใช้ gmail เป็นการทดสอบหรือเซิร์ฟเวอร์ SMTP ที่ใช้งานจริงให้เปิดใช้งานชั่วคราวหรือเข้าถึงแอปที่มีความปลอดภัยน้อยกว่าอย่างถาวร:

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.