파이썬으로 이메일을 보내는 방법?


169

이 코드는 작동하며 전자 메일을 보냅니다.

import smtplib
#SERVER = "localhost"

FROM = 'monty@python.com'

TO = ["jon@mycompany.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('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

누구든지 왜 내가 이해하도록 도울 수 있습니까?


2
함수를 어떻게 호출합니까?
Jochen Ritzel 2016 년

들여 쓰기가 파일에있는 것과 동일합니까?
gddc

@gddc 아니오 제대로 들여 쓰기를했는지 확인했습니다. 바로 붙여 넣기 방식입니다.
cloud311

기본 모듈로 가져 와서 정의한 매개 변수를 전달하여 함수를 호출합니다.
cloud311

4
이메일 패키지를 사용하는 @Arrieta의 제안이이를 해결하는 가장 좋은 방법이지만 귀하의 접근 방식은 효과적입니다. 두 버전의 차이점은 문자열에 있습니다. (1) @NickODell이 지적했듯이 함수 버전에는 공백이 있습니다. 헤더에는 줄 바꿈이없는 한 선행 공간이 없어야합니다. (2) TEXT에 빈 줄이 포함되어 있지 않으면 머리글과 본문 사이의 구분 기호가 없어집니다.
Tony Meyer 2018 년

답변:


191

표준 패키지 emailsmtplib함께 사용하여 전자 메일을 보내는 것이 좋습니다 . 다음 예제를 살펴보십시오 ( Python 문서 에서 재현 됨 ). 이 접근 방식을 따르면 "간단한"작업이 간단하고 이진 개체 첨부 또는 일반 / 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()

여러 대상으로 전자 메일을 보내려면 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함수에 대한 두 번째 인수 는 문자열 목록이어야합니다 (각 문자열은 전자 메일 주소 임).

세 개의 이메일 주소가 경우에 따라서, : person1@example.com, person2@example.com, 그리고 person3@example.com, 당신이 할 수있는 등 (명백한 부분은 생략) 다음과 같습니다 :

to = ["person1@example.com", "person2@example.com", "person3@example.com"]
msg['To'] = ",".join(to)
s.sendmail(me, to, msg.as_string())

",".join(to)부분은 목록에서 단일 문자열을 쉼표로 구분하여 만듭니다.

당신의 질문에서 나는 당신이 파이썬 튜토리얼 을 겪지 않았다는 것을 모았습니다 -파이썬의 어느 곳에서나 가고 싶다면 반드시 있어야합니다-문서는 표준 라이브러리에 대해 훌륭합니다.


1
이것은 기능 내에서 매우 훌륭하게 작동하지만 고맙지 만 여러 수신자에게 어떻게 보낼 수 있습니까? msg [to]가 사전 키인 것처럼 보이기 때문에 msg [to]를 세미콜론으로 분리하려고 시도했지만 작동하지 않는 것 같습니다.
cloud311

1
코드에있는 그대로 @ cloud311. 쉼표로 구분 된 문자열을 원합니다 : ", ".join(["a@example.com", "b@example.net"])
Tim McNamara

3
또한 To : 헤더는 봉투 수신자와 의미가 다릅니다. 예를 들어 ': Tony Meyer'<tony.meyer@gmail.com> '을 To : 헤더의 주소로 사용할 수 있지만 봉투 수신자는 "tony.meyer@gmail.com"이어야합니다. 'nice'To : 주소를 만들려면 email.utils.formataddr ( "Tony Meyer", "tony.meyer@gmail.com")와 같은 email.utils.formataddr을 사용하십시오.
Tony Meyer 2018 년

1
작은 개선 : 파일을 사용하여 열 수 있어야 with: with open(textfile, 'rb') as fp:. with블록은 파일 내부에서 오류가 발생하더라도 파일을 닫으므로 명시 적 닫기를 삭제할 수 있습니다 .
jpmc26

1
이 답변에만 국한되지는 않지만 제어하지 않는 SMTP 서버에 연결할 때는 연결할 수 없거나 느리거나 연결을 거부 할 수있는 가능성 등을 고려해야합니다. 코드 측면에서는 예외가 발생하지만 나중에 다시 전송을 다시 시도하는 방법을 찾아야합니다. 당신이 당신의 sendmail / postfix와 대화한다면, 그것은 당신을 위해 그 재전송을 처리 할 것입니다.
랄프 볼튼

66

글쎄, 당신은 최신의 현대적인 답변을 원합니다.

내 대답은 다음과 같습니다.

파이썬으로 메일을 보내야 할 때 메일 API를 사용하면 메일을 정렬하는 데 많은 어려움을 겪 습니다. 그들은 멋진 앱 / API를 가지고있어 매월 10,000 개의 이메일을 무료로 보낼 수 있습니다.

이메일을 보내는 것은 다음과 같습니다 :

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": ["bar@example.com", "YOU@YOUR_DOMAIN_NAME"],
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!"})

이벤트 및 기타 정보를 추적 할 수도 있습니다 . 빠른 시작 안내서를 참조하십시오 .

이 정보가 도움이 되길 바랍니다.


3
이것은 실제로 훨씬 더 "이 날짜"입니다. 외부 API를 사용하지만 나는 개인적으로 yagmail 과 같은 것을 내부적으로 유지하기 위해 사용합니다 .
PascalVKooten

6
@PascalvKooten yagmail에 대한 끊임없는 광고를 따르는 것이 절대적으로 재미 있습니다 (예, 선생님, 다음 번에 고려하겠습니다, 선생님;). 그러나 거의 아무도 OP 문제를 신경 쓰지 않는 것처럼 보이지만 오히려 다른 솔루션을 제안한다는 것은 매우 혼란 스럽습니다. 마치 2009 년 스마트 전구에서 전구를 교체하는 방법을 묻는 것과 같습니다. 실제 메르세데스를 구입하십시오.
flaschbier

내 임무는 일부 오락 가치가있는 것이 좋습니다.
PascalVKooten

4
@flaschbier OP 문제에 대해 아무도 신경 쓰지 않는 이유는 제목이 잘못 되었기 때문입니다. "파이썬으로 이메일을 보내는 방법?" 사람들이 그 질문을 클릭 할 때 실제로 보게되는 이유이며, yagmail 이 제공 할 수 있는 대답은 훌륭하고 짧습니다. 당신은 간다. 더 많은 yagmail 광고.
PascalVKooten

1
Mailgun 고객의 경우 웹 서비스로 메일을 보내는 것이 SMTP를 통해 (특히 첨부 파일을 사용하는 경우)보다 대역폭에 훨씬 친숙합니다.
랄프 볼튼

44

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.


4
이것이 최고의 솔루션이어야합니다.
Richard de Ree

1
OMG, 그것은 달콤하고 간단한 이메일 모듈입니다. 감사!
pepoluan

1
yagmailGmail 이외의 다른 것을 사용할 수 있습니까 ? 자체 SMTP 서버에 사용하려고합니다.
Anirban Nag 'tintinmj'6

@dtgq 걱정 해 주셔서 감사합니다. 개인적으로는 공격 벡터가 보이지 않습니다. 누군가가 보내려는 경로 아래에서 파일을 변경하려는 경우 Attachment수업 이 있는지는 중요하지 않습니다 . 여전히 같은 것입니다. 그들이 코드를 변경할 수 있다면 어쨌든 원하는 것을 할 수 있습니다 (루트 유무에 관계없이 동일한 wrt 이메일 전송). 이것은 일반적인 "편리하고 마술 적이므로 덜 안전해야한다"고 생각합니다. 실제 위협이 무엇인지 궁금합니다.
PascalVKooten

14

들여 쓰기 문제가 있습니다. 아래 코드는 작동합니다 :

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


3
@geotheory SERVER함수에 전달 된 변수는 사용자 자격 증명입니다.
사용자

간단한 문자열 보간을 사용하여 유효한 SMTP 메시지를 수동으로 연결하는 것은 권장되지 않으며 답변에이를 완벽하게 나타내는 버그가 있습니다. (본문은 유효한 메시지가 되려면 빈 줄로 시작해야합니다.) 1980 년대 7 비트 영어 전용 US-ASCII (첨부 파일, 국제화 및 기타 MIME 지원)의 일반 텍스트 이외의 문자 집합과 관련된 모든 경우 실제로이 물건을 처리하는 라이브러리를 사용하고 싶습니다. 파이썬 email라이브러리는이 작업을 특히 잘 수행하지만 (특히 3.6 이후) 수행중인 작업에 대한 이해가 여전히 필요합니다.
트리플 리

7

다음은 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='xx@example.com'):
    # 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=['12345@qq.com', '12345@126.com'],
          subject='hello', message='Your analysis has done!')

아래는 중국 사용자에게만 해당 될 수 있습니다.

126/163, 网易 邮箱을 사용하는 경우 아래와 같이 "客户 端 授权 密码"를 설정해야합니다.

여기에 이미지 설명을 입력하십시오

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


4

함수에서 코드를 들여 쓰는 동안 (괜찮아) 원시 메시지 문자열의 줄도 들여 쓰기했습니다. 그러나 선행 공백은 RFC 2822-인터넷 메시지 형식 의 섹션 2.2.3 및 3.2.3에 설명 된대로 헤더 행의 접힘 (연결)을 의미합니다 .

각 헤더 필드는 논리적으로 필드 이름, 콜론 및 필드 본문을 포함하는 한 줄의 문자입니다. 그러나 편의상, 라인 당 998/78 문자 제한을 처리하기 위해 헤더 필드의 필드 본문 부분을 여러 줄 표현으로 나눌 수 있습니다. 이것을 "폴딩"이라고합니다.

sendmail호출 의 함수 형식 에서 모든 행은 공백으로 시작하므로 "펼쳐짐"(연결됨)으로 보내려고합니다.

From: monty@python.com    To: jon@mycompany.com    Subject: Hello!    This message was sent with Python's smtplib.

우리의 마음이 시사하는 것보다 기타, smtplib이해하지 못할 To:Subject:이러한 이름 만 줄의 시작 부분에 인식하고 있기 때문에, 더 이상 헤더를. 대신 smtplib매우 긴 발신자 이메일 주소를 가정합니다.

monty@python.com    To: jon@mycompany.com    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: monty@python.com
To: jon@mycompany.com
Subject: Hello!

This message was sent with Python's smtplib.

이것이 작동하고 이전 코드로 수행 된 작업입니다.

필자는 RFC의 3.5 섹션 (필수) 을 수용하기 위해 헤더와 본문 사이에 빈 줄을 유지하고 Python 스타일 가이드 PEP-0008 (선택 사항) 에 따라 포함을 함수 외부에 두었습니다 .


3

아마도 메시지에 탭을 넣을 수 있습니다. sendMail에 전달하기 전에 메시지를 인쇄하십시오.


1

이메일 계정의 알 수없는 출처 (외부 소스)에서 이메일을 보내고 이메일을받을 수있는 권한을 발신자와 수신자 모두에게 부여했는지 확인하십시오.

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)

여기에 이미지 설명을 입력하십시오


msg는 유효한 SMTP 메시지가 아니며 메일 서버가 수락하면 간단하게 ether로 사라집니다.
트리플 리

0

이것이 어떻게 작동하는지 알아 냈기 때문에 여기에 두 비트를 넣을 것이라고 생각했습니다.

SERVER 연결 설정에 지정된 포트가없는 것 같습니다. 기본 포트를 사용하지 않는 SMTP 서버에 연결하려고 할 때 약간 영향을 미쳤습니다. 25.

smtplib.SMTP 문서에 따르면, ehlo 또는 helo 요청 / 응답이 자동으로 처리되어야하므로 걱정할 필요는 없습니다 (그러나 다른 모든 것이 실패하면 확인해야 할 수도 있습니다).

또 다른 질문은 SMTP 서버 자체에서 SMTP 연결을 허용 했습니까? GMAIL 및 ZOHO와 같은 일부 사이트의 경우 실제로 이메일 계정 내에서 IMAP 연결을 시작하고 활성화해야합니다. 메일 서버가 아마도 'localhost'에서 온 SMTP 연결을 허용하지 않을 수 있습니까? 살펴볼 것이 있습니다.

마지막으로 TLS에서 연결을 시도하고 시작할 수 있습니다. 대부분의 서버는 이제이 유형의 인증이 필요합니다.

이메일에 두 개의 TO 필드가 걸렸음을 볼 수 있습니다. msg [ 'TO'] 및 msg [ 'FROM'] msg 사전 항목을 사용하면 전자 메일의 머리글에 올바른 정보를 표시 할 수 있으며 전자 메일의 수신 끝에서받는 사람 / 보낸 사람 필드에 표시됩니다 (사용자 여기에 회신 필드를 추가 할 수도 있습니다 .TO 및 FROM 필드 자체는 서버에 필요한 것입니다. 일부 이메일 서버에 적절한 이메일 헤더가없는 경우 이메일을 거부하는 것으로 들었습니다.

이것은 로컬 컴퓨터와 원격 SMTP 서버 (그림과 같이 ZOHO)를 사용하여 * .txt 파일의 내용을 전자 메일로 보내는 기능에서 사용한 코드입니다.

def emailResults(folder, filename):

    # body of the message
    doc = folder + filename + '.txt'
    with open(doc, 'r') as readText:
        msg = MIMEText(readText.read())

    # headers
    TO = 'to_user@domain.com'
    msg['To'] = TO
    FROM = 'from_user@domain.com'
    msg['From'] = FROM
    msg['Subject'] = 'email subject |' + filename

    # SMTP
    send = smtplib.SMTP('smtp.zoho.com', 587)
    send.starttls()
    send.login('from_user@domain.com', 'password')
    send.sendmail(FROM, TO, msg.as_string())
    send.quit()

0

SMTP 모듈이 컨텍스트 관리자를 지원하므로 quit ()를 수동으로 호출 할 필요가 없으므로 예외가있는 경우에도 항상 호출됩니다.

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

-1

코드에 관해서는 근본적으로 문제가없는 것 같습니다. 단, 실제로 해당 함수를 호출하는 방법이 확실하지 않습니다. 내가 생각할 수있는 것은 서버가 응답하지 않으면이 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 에서 함수 호출을 사용하여 이메일을 보내는 예제를 확인하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.