Wysyłanie poczty z Pythona przy użyciu SMTP

118

Używam następującej metody do wysyłania poczty z Pythona przy użyciu SMTP. Czy jest to właściwa metoda, czy też brakuje mi jakichś pułapek?

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 <[email protected]>"
to_addr = "[email protected]"

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()
Eli Bendersky
źródło
2
Upewnij się, że data / godzina są prawidłowe. Uważam, że następująca funkcja jest całkiem przydatna, która daje idealnie sformatowaną wartość dla nagłówka daty
BastiBen
oto przykład kodu, który demonstruje, jak wysyłać obrazy w tekście (plus e-mail z częściami html i zwykłym tekstem) . Pokazuje również, jak skonfigurować parametry ssl w starszych wersjach Pythona.
jfs
2
Zauważ, że dostępne są biblioteki wrapperów, które sprawiają, że wysyłanie e-maili jest o wiele mniej kodowe (takie jak yagmail )
PascalVKooten

Odpowiedzi:

111

Skrypt, którego używam, jest dość podobny; Umieszczam to tutaj jako przykład wykorzystania modułów email. * Do generowania wiadomości MIME; więc ten skrypt można łatwo zmodyfikować, aby dołączyć zdjęcia itp.

Polegam na moim dostawcy usług internetowych, aby dodać nagłówek daty i godziny.

Mój dostawca usług internetowych wymaga ode mnie używania bezpiecznego połączenia SMTP do wysyłania poczty, polegam na module smtplib (do pobrania pod adresem http://www1.cs.columbia.edu/~db2501/ssmtplib.py )

Podobnie jak w Twoim skrypcie, nazwa użytkownika i hasło (podane poniżej wartości fikcyjne) używane do uwierzytelniania na serwerze SMTP są w źródle zwykłym tekstem. To jest słabość bezpieczeństwa; ale najlepsza alternatywa zależy od tego, jak ostrożnie musisz (chcesz?) dbać o ich ochronę.

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

#! /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
Vincent Marchetti
źródło
1
@Vincent: poczta nie powiodła się; Obiekt „module” nie ma atrybutu „SSLFakeSocket” - przy użyciu Gmaila :(
RadiantHex
To brzmi jak problem z wersją lub importem, aby pomóc go wyśledzić: Jaką wersję Pythona używasz? - Czy musisz łączyć się ze swoim serwerem SMTP przez SSL (a jeśli tak, to czy importujesz ssmtplib, jak wyżej)? Czy możesz zaimportować smtplib bezpośrednio z Python Interactive, jeśli tak, czy jest zdefiniowana klasa smtplib.SSLFakeSocket? Mam nadzieję, że mogę pomóc
Vincent Marchetti
2
Użyj smtplib.SMTP_SSL (standard w najnowszych wersjach Pythona), aby utworzyć połączenie zamiast ssmtplib.STMP_SSL (moduł innej firmy wskazany powyżej). Zauważ, że standardowy moduł zaczyna się pojedynczym „s”. To zadziałało dla mnie.
Julio Gorgé
2
wymienić from ssmtplib import SMTP_SSL as SMTPze from smtplib import SMTP_SSL as SMTPi ten przykład będzie działać ze standardowej biblioteki Pythona.
Adam Matan,
9
Dodaj msg['To'] = ','.join(destination), w przeciwnym razie miejsce docelowe nie jest wyświetlane w Gmailu
Taha Jahangir
88

Metoda, której często używam ... niewiele się różni, ale trochę

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

msg = MIMEMultipart()
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
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('[email protected]', 'mypassword')

mailserver.sendmail('[email protected]','[email protected]',msg.as_string())

mailserver.quit()

Otóż ​​to

szaleniec2890
źródło
Jeśli korzystasz z weryfikacji dwuetapowej, musisz najpierw utworzyć hasło aplikacji i zastąpić nim swoje zwykłe hasło. Zobacz Logowanie przy użyciu haseł do aplikacji
Suzana,
2
Zgadzam się, to najlepsza odpowiedź i należy ją zaakceptować. Ten, który jest faktycznie akceptowany, jest gorszy.
HelloWorld
6
W przypadku pythona3 użyj:from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
art
21

Również jeśli chcesz wykonać uwierzytelnianie smtp z TLS w przeciwieństwie do SSL, musisz po prostu zmienić port (użyj 587) i wykonaj smtp.starttls (). To zadziałało dla mnie:

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

źródło
6

Główną wadą, jaką widzę, jest to, że nie obsługujesz żadnych błędów: .login () i .sendmail () mają udokumentowane wyjątki, które mogą zgłaszać, i wygląda na to, że .connect () musi mieć jakiś sposób wskazania, że ​​tak było nie można się połączyć - prawdopodobnie wyjątek zgłoszony przez podstawowy kod gniazda.

pjz
źródło
6

Upewnij się, że nie masz żadnych zapór blokujących SMTP. Gdy pierwszy raz próbowałem wysłać wiadomość e-mail, została ona zablokowana zarówno przez Zaporę systemu Windows, jak i przez McAfee - znalezienie ich obu zajęło wieczność.

Mark Okup
źródło
6

A co z tym?

import smtplib

SERVER = "localhost"

FROM = "[email protected]"
TO = ["[email protected]"] # 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()
Satish
źródło
4

następujący kod działa dobrze dla mnie:

import smtplib

to = '[email protected]'
gmail_user = '[email protected]'
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()

Ref: http://www.mkyong.com/python/how-do-send-email-in-python-via-smtplib/

Abdul Majeed
źródło
1
Flask ma strukturę dla poczty e-mail: from flask.ext.mail import Mail. Rozwiązuję ten problem i pomyślałem, że wrócę do kodu Pythona, aby zobaczyć, czy uda mi się coś uruchomić. Podobała mi się ta odpowiedź, ponieważ były to nagie kości. O tak, i zadziałało!
Uwaga: poprzednia wersja odpowiedzi zawierała wiersz: smtpserver.close()Musi to być:, smtpserver.quit()ponieważ close()nie zakończy poprawnie połączenia TLS! close()zostanie wywołana w trakcie quit().
aronadaal
Cześć, mam problem z uruchomieniem powyższych poleceń. kiedy używam smtpserver.starttls (), otrzymuję błąd SMTP "SMTPServerDisconnected: Połączenie nieoczekiwanie zamknięte: [Errno 10054]" .. zgłoszone w stackoverflow.com/questions/46094175/ ...
fazkan
3

Powinieneś upewnić się, że formatujesz datę w odpowiednim formacie - RFC2822 .

Douglas Leeder
źródło
3

Przykładowy kod, który zrobiłem do wysyłania poczty przy użyciu 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()
Hariharan AR
źródło
2

Widzisz te wszystkie obszerne odpowiedzi? Proszę, pozwólcie mi się promować, robiąc to wszystko w kilku linijkach.

Importuj i połącz:

import yagmail
yag = yagmail.SMTP('[email protected]', host = 'YOUR.MAIL.SERVER', port = 26)

W takim razie jest to tylko jedna linijka:

yag.send('[email protected]', 'hello', 'Hello\nThis is a mail from your server\n\nBye\n')

W rzeczywistości zamknie się, gdy znajdzie się poza zakresem (lub może zostać zamknięty ręcznie). Ponadto pozwoli ci to zarejestrować swoją nazwę użytkownika w swojej bazie kluczy, dzięki czemu nie będziesz musiał wpisywać hasła w swoim skrypcie (naprawdę przeszkadzało mi to przed napisaniem yagmail!)

Aby zapoznać się z pakietem / instalacją, wskazówkami i sztuczkami, spójrz na git lub pip , dostępne zarówno dla Pythona 2, jak i 3.

PascalVKooten
źródło
@PascalvKoolen Zainstalowałem yagmail i próbowałem się połączyć, podając mój identyfikator e-mail i hasło. ale dało mi to błąd uwierzytelniania
fazkan
0

możesz to zrobić

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 = '[email protected]'
to = '[email protected]'
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)
Skiller Dz
źródło
0

Oto działający przykład dla Pythona 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 = '[email protected]'
password = getpass('Enter Gmail password: ')

sender = '[email protected]'
destination = '[email protected]'
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)))
znak
źródło
0

Na podstawie tego przykładu wykonałem następującą funkcję:

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

jeśli tylko zdasz, bodyzostanie wysłana zwykła wiadomość tekstowa, ale jeśli przekażesz htmlargument wraz zbody argumentem, zostanie wysłany e-mail w formacie HTML (z powrotem do treści tekstowej dla klientów poczty e-mail, które nie obsługują typów html / mime).

Przykładowe użycie:

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

Przy okazji. Jeśli chcesz używać Gmaila jako testowego lub produkcyjnego serwera SMTP, włącz tymczasowy lub stały dostęp do mniej zabezpieczonych aplikacji:

Robert Lujo
źródło