web-dev-qa-db-ja.com

Pythonでメールを送るにはどうすればいいですか?

このコードはうまくいき、私にEメールを送るだけでいいのです。

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

しかし、私がこのような関数でそれをラップしようとするなら:

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

それを呼び出すと、次のようなエラーが表示されます。

 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

誰かが私がその理由を理解するのを手伝ってくれる?

143
cloud311

標準パッケージの emailsmtplib を一緒に使用してEメールを送信することをお勧めします。次の例を見てください( Python documentation から転載)。このアプローチに従えば、「単純な」タスクは本当に単純であり、より複雑なタスク(バイナリオブジェクトの添付やプレーン/ HTMLマルチパートメッセージの送信など)は非常に迅速に実行されることに注意してください。

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

複数の宛先にEメールを送信する場合は、 Pythonのドキュメント の例に従うこともできます。

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

ご覧のとおり、ToオブジェクトのヘッダーMIMETextは、電子メールアドレスをコンマで区切った文字列でなければなりません。一方、sendmail関数の2番目の引数は文字列のリストでなければなりません(各文字列は電子メールアドレスです)。

そのため、[email protected][email protected]、および[email protected]の3つの電子メールアドレスがある場合は、次のようにします(明らかなセクションは省略されています)。

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

"","".join(to)部分は、リストからコンマで区切られた単一の文字列を作成します。

あなたの質問から私はあなたが経験したことがないことを集める Pythonチュートリアル - あなたがPythonのどこかに行きたいのならそれは絶対に必要である - ドキュメンテーションは標準ライブラリにとって大抵素晴らしい。

167
Escualo

さて、あなたは最新かつ現代的な答えを持ちたいです。

これが私の答えです:

私がpythonでメールを送る必要があるとき、私は mailgun APIを使います。彼らはあなたが無料で毎月10,000の電子メールを送信することを可能にする素晴らしいapp/apiを持っています。

電子メールを送ることはこのようになるでしょう:

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 <mailgun@YOUR_DOMAIN_NAME>",
              "to": ["[email protected]", "YOU@YOUR_DOMAIN_NAME"],
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!"})

イベントやもっとたくさんのことを追跡することもできます。 クイックスタートガイド をご覧ください。

これが役に立つことを願っています!

60
Dennis Decoene

私はyagmailパッケージに助言を与えることによってあなたに電子メールを送るのを手伝いたいです(私はメンテナです、広告を残念に思います、しかし、私はそれが本当に役に立つことができると思います!).

あなたのための全体のコードは次のようになります。

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

私はすべての引数にデフォルト値を提供していることに注意してください。例えば、あなたが自分自身に送信したい場合はTOを省略することができます。件名が不要な場合は省略することもできます。

さらに、目標は、HTMLコードや画像(およびその他のファイル)を添付するのを本当に簡単にすることです。

コンテンツを置く場所では、次のようなことができます。

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']

うわー、添付ファイルを送信するのはとても簡単です!これはyagmailなしで20行ほどかかるでしょう;)

また、一度設定すれば、もう一度パスワードを入力する必要はありません(そして安全に保管しておく必要があります)。あなたの場合は、次のようなことができます。

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

これはもっと簡潔です。

github をご覧になるか、pip install yagmailを使って直接インストールしてください。

35
PascalVKooten

くぼみの問題があります。以下のコードはうまくいきます。

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

14
Zeeshan

これを試して:

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)
    "New part"
    server.starttls()
    server.login('username', 'password')
    server.sendmail(FROM, TO, message)
    server.quit()

それはsmtp.gmail.comのために働きます

8
Theoremiser

関数内でコードをインデントしながら(これで問題ありません)、生のメッセージ文字列の行もインデントしました。しかし、先頭の空白は、 RFC 2822 - インターネットメッセージフォーマット のセクション2.2.3および3.2.3で説明されているように、ヘッダー行の折りたたみ(連結)を意味します。

各ヘッダーフィールドは、論理的にはフィールド名、コロン、およびフィールド本体を構成する1行の文字です。ただし、便宜上、1行あたりの998/78文字の制限を処理するために、ヘッダーフィールドのフィールド本体部分を複数行の表現に分割することができます。これは「折りたたみ」と呼ばれます。

sendmail呼び出しの関数形式では、すべての行が空白文字で始まっているため、「展開」されており(連結されている)、送信しようとしています。

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

私たちの考えではないが、smtplibTo:Subject:ヘッダーをもう理解しないだろう。なぜならこれらの名前は行頭でしか認識されないからである。代わりにsmtplibは非常に長い送信者Eメールアドレスを想定します。

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

これはうまくいかないので、例外があります。

解決方法は簡単です。文字列messageを以前の状態のままにするだけです。これは関数によって(Zeeshanが提案したように)実行することも、ソースコードですぐに実行することもできます。

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

今展開は起こらず、あなたは送る

From: [email protected]
To: [email protected]
Subject: Hello!

This message was sent with Python's smtplib.

これが機能し、古いコードによって行われたことです。

私はヘッダとボディの間の空行も保存していたことに注意してください。 RFC のセクション3.5(これは必須です)とPythonスタイルガイドに従ってインクルードを関数の外側に置きます。 PEP-0008 (これはオプションです).

4
flaschbier

それはおそらくあなたのメッセージにタブを入れることです。 sendMailに渡す前にメッセージを印刷してください。

3
Nick ODell

これは、Pythonの3.xの例です。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.')

この関数を呼び出します。

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

以下は中国人ユーザーの場合のみ可能です。

あなたが126/163、网易邮箱を使用するならば、あなたは以下のように "客户端授证密コード"を設定する必要があります:

enter image description here

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

2
Belter

SenderとReceiverの両方に、電子メールアカウント内の未知の送信元(外部送信元)から電子メールの送信および受信を許可する許可を与えていることを確認してください。

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)

enter image description here

2
Devanand Sharma

あなたのコードが関係している限りでは、それ以外は基本的に間違っているようには思われません。私が考えることができるすべてはあなたのサーバーが応答していないときあなたはこのSMTPServerDisconnectedエラーを受け取ることです。 smtplibでgetreply()関数を検索すると(以下の抜粋)、アイデアが得られます。

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.
    """

https://github.com/rreddy80/sendEmails/blob/master/sendEmailAttachments.py で例をチェックしてください。 (ドライアプローチ)。

0
rreddy

私はこれがどのように機能するかを考え出したので、私はここに私の2つのビットを入れたいと思いました。

デフォルトのポートを使用していないSMTPサーバーに接続しようとしたときに、サーバーの接続設定でポートが指定されていないようです。25。

Smtplib.SMTPのドキュメントによると、あなたのehloやheloのリクエスト/レスポンスは自動的に処理されるはずなので、これについて心配する必要はありません(しかし、他のすべてが失敗した場合に確認するものかもしれません)。

あなた自身に尋ねるべきもう一つのことはあなたがあなたのSMTPサーバ自体の上でSMTP接続を許可したか? GMAILやZOHOなどの一部のサイトでは、実際にアクセスして電子メールアカウント内でIMAP接続を有効にする必要があります。あなたのメールサーバはおそらく 'localhost'から来ていないSMTP接続を許可しないかもしれません?調べる何か。

最後に、TLSで接続を試してみることをお勧めします。ほとんどのサーバーは現在このタイプの認証を必要とします。

あなたは私が私の電子メールに2つのTOフィールドを詰め込んでいるのを見るでしょう。 msg ['TO']およびmsg ['FROM'] msgディクショナリ項目を使用すると、正しい情報を電子メール自体のヘッダーに表示できます。これは、電子メールの受信側の[To/From]フィールドに表示されます。 TOフィールドとFROMフィールド自体はサーバーが必要とするものであり、適切なEメールヘッダーがない場合、Eメールを拒否するEメー​​ルサーバーがあることを私は知っています。

これは私がローカルのコンピュータとリモートのSMTPサーバを使って* .txtファイルの内容を電子メールで送るために使う関数の中で使ったコードです(ZOHO)。

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