Hoe stuur je een e-mail met Python?

Deze code werkt en stuurt me prima een e-mail:

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('myserver')
server.sendmail(FROM, TO, message)
server.quit()

Als ik het echter in een functie als deze probeer in te pakken:

def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    import smtplib
    """this is some test documentation in the function"""
    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()

en noem het ik krijg de volgende fouten:

Traceback (most recent call last):
  File "C:/Python31/mailtest1.py", line 8, in <module>
    sendmail.sendMail(sender,recipients,subject,body,server)
  File "C:/Python31\sendmail.py", line 13, in sendMail
    server.sendmail(FROM, TO, message)
  File "C:\Python31\lib\smtplib.py", line 720, in sendmail
    self.rset()
  File "C:\Python31\lib\smtplib.py", line 444, in rset
    return self.docmd("rset")
  File "C:\Python31\lib\smtplib.py", line 368, in docmd
    return self.getreply()
  File "C:\Python31\lib\smtplib.py", line 345, in getreply
    raise SMTPServerDisconnected("Connection unexpectedly closed")
smtplib.SMTPServerDisconnected: Connection unexpectedly closed

Kan iemand me helpen begrijpen waarom?


Antwoord 1, autoriteit 100%

Ik raad u aan de standaardpakketten emailen smtplibsamen om e-mail te verzenden. Bekijk het volgende voorbeeld (overgenomen uit de Python-documentatie). Merk op dat als je deze aanpak volgt, de “eenvoudige” taak inderdaad eenvoudig is, en de meer complexe taken (zoals het toevoegen van binaire objecten of het verzenden van platte/HTML meerdelige berichten) zeer snel worden uitgevoerd.

# Import smtplib for the actual sending function
import smtplib
# Import the email modules we'll need
from email.mime.text import MIMEText
# Open a plain text file for reading.  For this example, assume that
# the text file contains only ASCII characters.
with open(textfile, 'rb') as fp:
    # Create a text/plain message
    msg = MIMEText(fp.read())
# me == the sender's email address
# you == the recipient's email address
msg['Subject'] = 'The contents of %s' % textfile
msg['From'] = me
msg['To'] = you
# Send the message via our own SMTP server, but don't include the
# envelope header.
s = smtplib.SMTP('localhost')
s.sendmail(me, [you], msg.as_string())
s.quit()

Als u e-mail naar meerdere bestemmingen wilt verzenden, kunt u ook het voorbeeld volgen in de Python documentatie:

# Import smtplib for the actual sending function
import smtplib
# Here are the email package modules we'll need
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
# Create the container (outer) email message.
msg = MIMEMultipart()
msg['Subject'] = 'Our family reunion'
# me == the sender's email address
# family = the list of all recipients' email addresses
msg['From'] = me
msg['To'] = ', '.join(family)
msg.preamble = 'Our family reunion'
# Assume we know that the image files are all in PNG format
for file in pngfiles:
    # Open the files in binary mode.  Let the MIMEImage class automatically
    # guess the specific image type.
    with open(file, 'rb') as fp:
        img = MIMEImage(fp.read())
    msg.attach(img)
# Send the email via our own SMTP server.
s = smtplib.SMTP('localhost')
s.sendmail(me, family, msg.as_string())
s.quit()

Zoals je kunt zien, moet de kop TOin het MIMEText-object een tekenreeks zijn die bestaat uit e-mailadressen gescheiden door komma’s. Aan de andere kant moet het tweede argument voor de functie sendmaileen lijst met tekenreeksen zijn (elke tekenreeks is een e-mailadres).

Dus als je drie e-mailadressen hebt: [email protected], [email protected]en [email protected], kunt u het volgende doen (voor de hand liggende secties weggelaten):

to = ["[email protected]", "[email protected]", "[email protected]"]
msg['To'] = ",".join(to)
s.sendmail(me, to, msg.as_string())

het ",".join(to)gedeelte maakt een enkele string uit de lijst, gescheiden door komma’s.

Van uw vragen die ik verzamel dat je niet hebt doorgemaakt de python tutorial – Het is een must als u ergens in Python wilt komen – de documentatie is meestal uitstekend voor de standaardbibliotheek.


Antwoord 2, Autoriteit 40%

Nou, u wilt een antwoord hebben dat up-to-date en modern is.

Hier is mijn antwoord:

Als ik in Python moet mailen, gebruik ik de mailgun api die veel van de hoofdpijn krijgt met verzending mails gesorteerd. Ze hebben een geweldige app / API waarmee u 5000 gratis e-mails per maand kunt verzenden.

Het verzenden van een e-mail zou zo zijn:

def send_simple_message():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
        auth=("api", "YOUR_API_KEY"),
        data={"from": "Excited User <[email protected]_DOMAIN_NAME>",
              "to": ["[email protected]", "[email protected]_DOMAIN_NAME"],
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!"})

U kunt ook evenementen en nog veel meer volgen, de QuickStart-gids .

Ik hoop dat je dit nuttig vindt!


Antwoord 3, Autoriteit 26%

Ik wil u graag helpen met het verzenden van e-mails door het Yagmail-pakket te adviseren (ik ben de beheerder, sorry voor de reclame, maar ik voel dat het echt kan helpen!).

De hele code voor u zou zijn:

import yagmail
yag = yagmail.SMTP(FROM, 'pass')
yag.send(TO, SUBJECT, TEXT)

Merk op dat ik standaardinstellingen voor alle argumenten geef, bijvoorbeeld als je naar jezelf wilt sturen, kun je TOweglaten, als je geen onderwerp wilt, kun je het ook weglaten.

Bovendien is het doel ook om het heel gemakkelijk te maken om html-code of afbeeldingen (en andere bestanden) bij te voegen.

Waar je inhoud plaatst, kun je zoiets doen als:

contents = ['Body text, and here is an embedded image:', 'http://somedomain/image.png',
            'You can also find an audio file attached.', '/local/path/song.mp3']

Wauw, wat is het gemakkelijk om bijlagen te verzenden! Dit zou ongeveer 20 regels duren zonder yagmail 😉

Als je het eenmalig instelt, hoef je het wachtwoord ook nooit meer in te voeren (en het veilig te bewaren). In jouw geval kun je zoiets doen als:

import yagmail
yagmail.SMTP().send(contents = contents)

wat veel beknopter is!

Ik nodig je uit om de githubte bekijken of direct te installeren met pip install yagmail.


Antwoord 4, autoriteit 8%

Er is een inspringingsprobleem. De onderstaande code werkt:

import textwrap
def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    import smtplib
    """this is some test documentation in the function"""
    message = textwrap.dedent("""\
        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()


Antwoord 5, autoriteit 5%

Hier is een voorbeeld van Python 3.x, veel eenvoudiger dan 2.x:

import smtplib
from email.message import EmailMessage
def send_mail(to_email, subject, message, server='smtp.example.cn',
              from_email='[email protected]'):
    # import smtplib
    msg = EmailMessage()
    msg['Subject'] = subject
    msg['From'] = from_email
    msg['To'] = ', '.join(to_email)
    msg.set_content(message)
    print(msg)
    server = smtplib.SMTP(server)
    server.set_debuglevel(1)
    server.login(from_email, 'password')  # user & password
    server.send_message(msg)
    server.quit()
    print('successfully sent the mail.')

roep deze functie aan:

send_mail(to_email=['[email protected]', '[email protected]'],
          subject='hello', message='Your analysis has done!')

hieronder mag alleen voor Chinese gebruikers:

Als u 126/163, 网易邮箱 gebruikt, moet u “客户端授权密码” instellen, zoals hieronder:

ref: https://stackoverflow.com/a/41470149/2803344
https://docs.python.org/3/library/email .examples.html#email-examples


Antwoord 6, autoriteit 2%

Terwijl u uw code in de functie inspringt (wat goed is), liet u ook de regels van de onbewerkte berichtreeks inspringen. Maar leidende witruimte impliceert vouwen (aaneenschakeling) van de kopregels, zoals beschreven in secties 2.2.3 en 3.2.3 van RFC 2822 – Indeling internetbericht:

Elk kopveld is logischerwijs een enkele regel met tekens, bestaande uit:
de veldnaam, de dubbele punt en de veldtekst. Voor het gemak
echter, en om te gaan met de 998/78 tekenbeperkingen per regel,
het veldlichaamsgedeelte van een kopveld kan worden opgesplitst in een veelvoud
lijn weergave; dit wordt “vouwen” genoemd.

In de functievorm van uw sendmail-aanroep beginnen alle regels met witruimte en zijn dus “uitgevouwen” (aaneengeschakeld) en u probeert te verzenden

From: [email protected]    To: [email protected]    Subject: Hello!    This message was sent with Python's smtplib.

Anders dan onze geest doet vermoeden, zal smtplibde koppen To:en Subject:niet meer begrijpen, omdat deze namen alleen worden herkend aan het begin van een regel. In plaats daarvan neemt smtplibeen erg lang e-mailadres van de afzender aan:

[email protected]    To: [email protected]    Subject: Hello!    This message was sent with Python's smtplib.

Dit werkt niet en dus komt je uitzondering.

De oplossing is simpel: behoud gewoon de messagestring zoals voorheen. Dit kan worden gedaan door een functie (zoals Zeeshan suggereerde) of meteen in de broncode:

import smtplib
def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    """this is some test documentation in the function"""
    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()

Nu de ontvouwing niet optreden en u verzendt

From: [email protected]
To: [email protected]
Subject: Hello!
This message was sent with Python's smtplib.

wat werkt en wat is gedaan door uw oude code.

Merk op dat ik ook de lege regel behoud tussen headers en instantie om sectie 3.5 van de RFC (die vereist is) en de omvatten buiten de functie plaatsen volgens de Python Style-gids Pep-0008 (die optioneel is).


Antwoord 7

Het is waarschijnlijk de tabbladen in uw bericht. Print het bericht voordat u deze doorgeeft aan Sendmail.


Antwoord 8

Ik dacht dat ik hier in mijn twee stukjes zou stoppen, omdat ik net heb ontdekt hoe dit werkt.

Het lijkt erop dat u de poort niet hebt opgegeven op de instellingen van uw serververbinding, dit bewerkte me een beetje als ik probeerde verbinding te maken met mijn SMTP-server die de standaardpoort niet gebruikt: 25.

Volgens de SMTPLIB.SMTPOCS moet uw EHLO- of HELO-verzoek / -antwoord automatisch worden verzorgd, dus u hoeft zich hier geen zorgen over te maken (maar misschien iets om te bevestigen als al het andere faalt).

Nog een ding om jezelf te vragen, is dat je SMTP-verbindingen op je SMTP-server zelf hebt toegestaan? Voor sommige sites zoals Gmail en Zoho moet je daadwerkelijk gaan en de IMAP-verbindingen in het e-mailaccount activeren. Uw e-mailserver heeft mogelijk geen SMTP-verbindingen toe die misschien niet van ‘localhost’ komen? Iets om naar te kijken.

Het laatste is dat u misschien wilt proberen en de verbinding op TLS kunt initiëren. De meeste servers vereisen nu dit type authenticatie.

Je zult zien dat ik twee naar velden heb vastgelopen in mijn e-mail. De MSG [‘To’] en MSG [‘from’] MSG Woordenboekitems maakt de juiste informatie mogelijk om in de headers van de e-mail zelf op te verschijnen, die men ziet op het ontvangende einde van de e-mail in de To / Off-velden (u Misschien zelfs in staat zijn om hier een antwoord op het veld in te voegen. De aan en naar velden zelf zijn wat de server nodig heeft. Ik weet dat ik heb gehoord van een aantal e-mailservers die e-mails afwijzen als ze niet de juiste e-mailoptien op zijn plaats hebben.

Dit is de code die ik heb gebruikt, in een functie die voor mij werkt om de inhoud van een * .txt-bestand te e-mailen met mijn lokale computer en een externe SMTP-server (Zoho zoals weergegeven):

def emailResults(folder, filename):
    # body of the message
    doc = folder + filename + '.txt'
    with open(doc, 'r') as readText:
        msg = MIMEText(readText.read())
    # headers
    TO = '[email protected]'
    msg['To'] = TO
    FROM = '[email protected]'
    msg['From'] = FROM
    msg['Subject'] = 'email subject |' + filename
    # SMTP
    send = smtplib.SMTP('smtp.zoho.com', 587)
    send.starttls()
    send.login('[email protected]', 'password')
    send.sendmail(FROM, TO, msg.as_string())
    send.quit()

Antwoord 9

Zorg ervoor dat u zowel de afzender als de ontvanger toestemming hebt gegeven om e-mail te verzenden en te ontvangen van onbekende bronnen (externe bronnen) in het e-mailaccount.

import smtplib
#Ports 465 and 587 are intended for email client to email server communication - sending email
server = smtplib.SMTP('smtp.gmail.com', 587)
#starttls() is a way to take an existing insecure connection and upgrade it to a secure connection using SSL/TLS.
server.starttls()
#Next, log in to the server
server.login("#email", "#password")
msg = "Hello! This Message was sent by the help of Python"
#Send the mail
server.sendmail("#Sender", "#Reciever", msg)


Antwoord 10

Het is vermeldenswaard dat de SMTP-module de contextmanager ondersteunt, dus het is niet nodig om handmatig quit( aan te roepen), dit garandeert dat het altijd wordt aangeroepen, zelfs als er een uitzondering is.

   with smtplib.SMTP_SSL('smtp.gmail.com', 465) as server:
        server.ehlo()
        server.login(user, password)
        server.sendmail(from, to, body)

Antwoord 11

Wat uw code betreft, lijkt er niets fundamenteel mis mee te zijn, behalve dat het onduidelijk is hoe u die functie eigenlijk aanroept. Het enige dat ik kan bedenken is dat wanneer uw server niet reageert, u deze SMTPServerDisconnected-fout krijgt. Als je de functie getreply() opzoekt in smtplib (uittreksel hieronder), krijg je een idee.

def getreply(self):
    """Get a reply from the server.
    Returns a tuple consisting of:
      - server response code (e.g. '250', or such, if all goes well)
        Note: returns -1 if it can't read response code.
      - server response string corresponding to response code (multiline
        responses are converted to a single, multiline string).
    Raises SMTPServerDisconnected if end-of-file is reached.
    """

bekijk een voorbeeld op https://github.com/rreddy80/sendEmails/ blob/master/sendEmailAttachments.pydie ook een functieaanroep gebruikt om een e-mail te verzenden, als dat is wat u probeert te doen (DRY-benadering).

Other episodes