Python3 socket.gaierror 然后调用 smtplib.SMTP

Python3 socket.gaierror then calling smtplib.SMTP

问题描述

我在 sendmail.py 中实现了通过 smtplib 发送电子邮件的功能。 在 main.py 我导入了 sendmail 并使用它。然后我 运行 main.py,它在 s = smtplib.SMTP(SMTP_SERVER):

上崩溃
Traceback (most recent call last):
  File "./main.py", line 30, in <module>
    main()
  File "./main.py", line 26, in main
    sendmail.send_email("alarm", images)
  File "/home/pi/src/alarm-system/new_meta/sendmail.py", line 76, in send_email
    s = smtplib.SMTP(SMTP_SERVER)
  File "/home/pi/.pyenv/versions/3.6.1/lib/python3.6/smtplib.py", line 251, in __init__
    (code, msg) = self.connect(host, port)
  File "/home/pi/.pyenv/versions/3.6.1/lib/python3.6/smtplib.py", line 335, in connect
    self.sock = self._get_socket(host, port, self.timeout)
  File "/home/pi/.pyenv/versions/3.6.1/lib/python3.6/smtplib.py", line 306, in _get_socket
    self.source_address)
  File "/home/pi/.pyenv/versions/3.6.1/lib/python3.6/socket.py", line 704, in create_connection
    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
  File "/home/pi/.pyenv/versions/3.6.1/lib/python3.6/socket.py", line 743, in getaddrinfo
    for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
socket.gaierror: [Errno -2] Name or service not known

我是如何找到解决方案的

首先,我在交互式 python3 和 ipython 中检查我的 sendmail 模块(在部署代码的同一系统上)。 在交互式 python/ipython 中,它就像一个魅力,成功发送了电子邮件,没有错误的回溯:

pi at raspberrypi in ~/src/alarm-system/new_meta (master)
$ /usr/bin/env python3
Python 3.6.1 (default, Jun 22 2017, 22:14:56)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sendmail
>>> sendmail.send_email("alarm",[])
True
>>>

我还检查了系统如何解析 smtp.gmail.com 和使用 telnet smtp.gmail.com 587,所以这不是连接/网络问题。

Note: I have installed latest python via pyenv, so /usr/bin/env python3 runs it. Python/iPython runs same version of python.

也许有人反驳过同样的问题?任何建议下一步调试什么?

代码

sendmail.py

#!/usr/bin/env python3
import smtplib
import mimetypes

from email import encoders
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.base import MIMEBase

import logging

logger = logging.getLogger(__name__)

SMTP_SERVER = "smtp.gmail.com:587"

# Function to send email with attachments or not.
# NOTE: attachments (files variable) must be a list of paths to files
def send_email(subj=None,files=None):
    msg = MIMEMultipart()

    if subj == "log":
        subject = LOG_SUBJ
    else:
        subject = ALARM_SUBJ

    msg["Subject"] = subject
    msg["From"] = FROM_EMAIL
    msg["To"] = TO_EMAIL

    if files is not None and type(files) == list:
        for filename in files:
            content_type, encoding = mimetypes.guess_type(filename)
            if content_type is None or encoding is not None:
                content_type = "application/octet-stream"
            maintype, subtype = content_type.split("/", 1)

            if maintype == "text":
                with open(filename) as fp:
                    file_attach = MIMEText(fp.read(), _subtype=subtype)
                attach_name = filename.split("/")[-1]
                file_attach.add_header('Content-Disposition', 'attachment',
                               filename=attach_name)
                msg.attach(file_attach)
                logger.info("Text file detected and attached. File: %s",
                            filename)
            elif maintype == "image":
                with open(filename, "rb") as fp:
                    file_attach = MIMEImage(fp.read(), _subtype=subtype)
                attach_name = filename.split("/")[-1]
                file_attach.add_header('Content-Disposition', 'attachment',
                               filename=attach_name)
                msg.attach(file_attach)
                logger.info("Image file detected and attached. File: %s",
                            filename)
            else:
                with open(filename,"rb") as fp:
                    file_attach = MIMEBase(maintype, subtype)
                    file_attach.set_payload(fp.read())
                encoders.encode_base64(file_attach)

                msg.attach(file_attach)
                logger.info("Base64 file detected and attached. File: %s",
                            filename)
    elif files is None:
        msg += MIMEText("Alarm raised, no attachments files")


    composed = msg.as_string()
    s = smtplib.SMTP(SMTP_SERVER)

    s.starttls()

    try:
        s.login(USERNAME, PASSWORD)
        s.sendmail(FROM_EMAIL, TO_EMAIL, composed)
        logger.info("Email sended successfully.")
        logger.info("Email attachments: %s", files)
        s.close()
        return True
    except Exception as err:
        logger.error("Email not send! Error message: %s", err)
        s.close()
        return False

main.py

#!/usr/bin/env python3
import logging
from time import sleep

from gpiozero import MotionSensor
from datetime import datetime

import camera
import sendmail

logging.basicConfig(filename="/var/log/alarm/alarm.txt", level=logging.INFO,
                        format="%(asctime)s - %(levelname)s - %(funcName)s - %(message)s")

logger = logging.getLogger(__name__)


def main():

    pir = MotionSensor(7)
    #pir.when_motion() = alarmLogging()
    while True:
        if pir.motion_detected:
            logger.warning("MOTION DETECTED")
            images = camera.capture_image(2)
            logging.info("Send images to email: %s", images)
            sendmail.send_email("alarm", images)
            sleep(10)

if __name__ == '__main__':
main()

经过一些研究,我找到了问题的解决方案:问题发生了,因为我在系统 python 版本旁边通过 pyenv 安装了最新的 python 版本。 看起来 python 与系统一起安装可以访问低级系统接口,例如套接字,然后新安装的 python 没有。 所以问题解决了,然后我运行我的代码与系统python(版本3.4.2)。