Search code examples
pythonsocketsemailpython-3.6smtplib

Python3 socket.gaierror then calling smtplib.SMTP


Problem description

I have implemented function to send email via smtplib in sendmail.py. In main.py I have imported sendmail and use it. Then I run main.py, it crashes on 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

How I tried to find out solution

First of all, I check my sendmail module in interactive python3 and ipython (on same system where code deployed). In interactive python/ipython it works like a charm, email successfully sent, no tracebacks with errors:

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

Also I have checked how system resolve smtp.gmail.com and use telnet smtp.gmail.com 587, so it is not connection / network issue.

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

Maybe someone countered same problem? Any advice what debug next?

Code

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

Solution

  • I have found solution of problem after some research: problem occured, because I've installed latest python release via pyenv beside system python version. It's looks like python installed with system have access to low level system interfaces such as sockets, then fresh installed python does not have. So the problem solved, then I run my code with system python (version 3.4.2).