Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 24, 2017 23:24:57

r0n41d
Зарегистрирован: 2017-01-24
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

smtplib и UnicodeEncodeError

Салют!
Уже приличное количество времени бьюсь лбом о стенку при попытке отправить письмо через Python (используемая версия - 3.5.2, все используемые библиотеки обновлены до последних на данный момент версий).
Пробую готовый код отсюда: Ссылка
Из изменений - только замена raw_input на input и корректировка названий в импортах

 #!/usr/bin/env python 
# -*- coding: utf-8 -*-
#
#       gmail.py
#
import sys
import os
import smtplib
import getpass
import configparser
from optparse import OptionParser
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
'''
Usage: gmail.py [options] arg1
Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -f FILE, --file=FILE  image FILE to attach
  -t EMAIL, --to=EMAIL  email destination
  -o NAME, --from=NAME  name of origin
  -b BODY, --body=BODY  BODY message
  -s SUBJECT, --subject=SUBJECT
                        SUBJECT message
Config file example "gmail.cfg"
[Default]
fromaddr = Server email Name
toaddrs  = destination@example.com
[Gmail]
username = MYGMAILUSER
password = MYGMAILPASS
'''
# Program epilog
epilog = \
"""
gmail is configured using a config file only. 
If none is supplied, it will read gmail.cfg 
from current directory or ~/.gmail.cfg.
"""
def main():
    usage = "usage: %prog [options] arg"
    version = "%prog 1.0"
    parser = OptionParser(usage=usage, version=version, epilog=epilog)
    parser.add_option("-f", "--file", dest="image_file",
                  help="image FILE to attach", metavar="FILE")
    parser.add_option("-c", "--conf", dest="config_file",
                  help="config FILE", metavar="CONFIG",
                  default='gmail.cfg')
    parser.add_option("-t", "--to", dest="toaddrs",
                  help="email destination", metavar="EMAIL",
                  default=None)
    parser.add_option("-o", "--from", dest="fromaddr",
                  help="name of origin", metavar="NAME",
                  default=None)
    parser.add_option("-b", "--body", dest="body",
                  help="BODY message", metavar="BODY",
                  default='')
    parser.add_option("-s", "--subject", dest="subject",
                  help="SUBJECT message", metavar="SUBJECT",
                  default='')
    (options, args) = parser.parse_args()
    # Run the program
    process(options, args)
def process(options, args):
    config = get_config(options)
    # Write the email
    msg = MIMEMultipart()
    msg['From'] = config['fromaddr']
    msg['To'] = config['toaddrs']
    msg['Subject'] = options.subject
    body = options.body
    msg.attach(MIMEText(body, 'plain'))
    # Attach image
    if options.image_file:
        try:
            filename = open(options.image_file, "rb")
            attach_image = MIMEImage(filename.read())
            attach_image.add_header('Content-Disposition', 
                                    'attachment; filename = %s'%options.image_file)
            msg.attach(attach_image)
            filename.close()
        except:
            msg.attach(MIMEText('Image attachment error', 'plain'))
    # Converting email to text
    text = msg.as_string()
    
    # The actual mail send
    server = smtplib.SMTP('smtp.gmail.com:587')
    server.ehlo()
    server.starttls()
    server.ehlo()
    server.login(config['username'],config['password'])
    server.sendmail(config['fromaddr'], config['toaddrs'], text)
    server.quit()
def get_config(options):
    conf = {}
    # Read Config File
    config = configparser.RawConfigParser()
    config.read([options.config_file, os.path.expanduser('~/.gmail.cfg')])
    # Gmail Credentials
    try:
        conf['username'] = config.get('Gmail', 'username')
        conf['password'] = config.get('Gmail', 'password')
    except:
        conf['username'] = input('Input Gmail username: ')
        conf['password'] = getpass.getpass('Input Gmail password: ')
    # Email Default
    if options.fromaddr == None:
        try:
            conf['fromaddr'] = config.get('Default', 'fromaddr')
        except:
            conf['fromaddr'] = 'Python Gmail'
    else:
        conf['fromaddr'] = options.fromaddr
    if options.toaddrs == None:
        try:
            conf['toaddrs']  = config.get('Default', 'toaddrs')
        except:
            conf['toaddrs'] = input('Input email destination: ')
    else:
        conf['toaddrs'] = options.toaddrs
    return conf
if __name__ == '__main__':
    main()

После запуска получаю ошибку:
Traceback (most recent call last):
File “C:\tester-xls\gmail.py”, line 136, in <module>
main()
File “C:\tester-xls\gmail.py”, line 72, in main
process(options, args)
File “C:\tester-xls\gmail.py”, line 99, in process
server.ehlo()
File “C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py”, line 439, in ehlo
self.putcmd(self.ehlo_msg, name or self.local_hostname)
File “C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py”, line 366, in putcmd
self.send(str)
File “C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py”, line 351, in send
s = s.encode(self.command_encoding)
UnicodeEncodeError: ‘ascii’ codec can't encode characters in position 5-6: ordinal not in range(128)

До этого использовал множество различных вариантов, включая использование OAuth для отправки через GMail (код был взят отсюда: Ссылка. Всё равно встречаю ошибку UnicodeEncodeError.

На форуме уже поднимались подобные вопросы, решения оттуда я тоже пытался применить, но везде встречаю такую же проблему, чем это может быть вызвано, и как с этим справиться?

Офлайн

#2 Янв. 25, 2017 00:53:54

wi34rd
Зарегистрирован: 2016-10-08
Сообщения: 89
Репутация: +  2  -
Профиль   Отправить e-mail  

Офлайн

#3 Янв. 25, 2017 04:13:24

r0n41d
Зарегистрирован: 2017-01-24
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

smtplib и UnicodeEncodeError

wi34rd
http://stackoverflow.com/questions/10295530/how-to-set-a-charset-in-email-using-smtplib-in-python-2-7
Не попаду к компьютеру на винде до следующего вечера, но вопрос возникает другой: на Mac, в той же IDE (PyCharm), с той же версией питона, всё работает идеально и без изменений. Как только попадает на PC - проблема. Причём, когда я ковырялся сам, я пробовал оставлять вообще только следующие строки:
    server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()
Всё равно говорит о том же самом юникоде. Варианты с encode я тоже пробовал, в конце концов пытался хотя бы несколько букв латинского алфавита отправить - одно и то же. Может ли это как-то быть связано вообще с системой?

Отредактировано r0n41d (Янв. 25, 2017 04:14:12)

Офлайн

#4 Янв. 26, 2017 00:47:14

wi34rd
Зарегистрирован: 2016-10-08
Сообщения: 89
Репутация: +  2  -
Профиль   Отправить e-mail  

smtplib и UnicodeEncodeError

И каждый раз у вас одна и та же ошибка?

UnicodeEncodeError: ‘ascii’ codec can't encode characters in position 5-6: ordinal not in range(128)

Офлайн

#5 Янв. 26, 2017 23:59:25

r0n41d
Зарегистрирован: 2017-01-24
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

smtplib и UnicodeEncodeError

wi34rd
И каждый раз у вас одна и та же ошибка?
Да, ошибка та же самая, иногда лишь меняются числа в её выводе.
С чем это может быть связано, ведь всё-таки возвращаясь к моему предыдущему посту - я даже на стадии ehlo валюсь.
 import smtplib
server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()

Даёт ошибку:

 Traceback (most recent call last):
  File "C:/Users/Пользователь/PycharmProjects/server-client-structure/gmail.py", line 4, in <module>
    server.ehlo()
  File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py", line 439, in ehlo
    self.putcmd(self.ehlo_msg, name or self.local_hostname)
  File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py", line 366, in putcmd
    self.send(str)
  File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py", line 351, in send
    s = s.encode(self.command_encoding)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 5-6: ordinal not in range(128)

UPD:
Запуск вне IDE тоже выдает ошибку, на этот раз такого вида:
C:\Users\Пользователь>C:\Users\Пользователь\PycharmProjects\server-client-struct
ure\gmail.py
Traceback (most recent call last):
File "C:\Users\Пользователь\PycharmProjects\server-client-structure\gmail.py",
line 5, in <module>
server = smtplib.SMTP('smtp.gmail.com:587')
File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python36-32\lib\smtp
lib.py", line 260, in __init__
fqdn = socket.getfqdn()
File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python36-32\lib\sock
et.py", line 673, in getfqdn
hostname, aliases, ipaddrs = gethostbyaddr(name)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xcf in position 0: invalid
continuation byte


UPD2:
После сотой попытки запустить код ошибка поменялась:
 C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\python.exe C:/Users/Пользователь/PycharmProjects/server-client-structure/gmail.py
Traceback (most recent call last):
  File "C:/Users/Пользователь/PycharmProjects/server-client-structure/gmail.py", line 5, in <module>
    server = smtplib.SMTP(host='mail.google.com', port=587)
  File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py", line 251, in __init__
    (code, msg) = self.connect(host, port)
  File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py", line 335, in connect
    self.sock = self._get_socket(host, port, self.timeout)
  File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\smtplib.py", line 306, in _get_socket
    self.source_address)
  File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\socket.py", line 711, in create_connection
    raise err
  File "C:\Users\Пользователь\AppData\Local\Programs\Python\Python35-32\lib\socket.py", line 702, in create_connection
    sock.connect(sa)
TimeoutError: [WinError 10060] Попытка установить соединение была безуспешной, т.к. от другого компьютера за требуемое время не получен нужный отклик, или было разорвано уже установленное соединение из-за неверного отклика уже подключенного компьютера
Process finished with exit code 1

Отредактировано r0n41d (Янв. 27, 2017 00:26:34)

Офлайн

#6 Янв. 27, 2017 02:11:10

r0n41d
Зарегистрирован: 2017-01-24
Сообщения: 4
Репутация: +  0  -
Профиль   Отправить e-mail  

smtplib и UnicodeEncodeError

Решение проблемы найдено:
Ошибка возникала при использовании метода starttls() на хостах с кириллицей в имени.
Решил топорно, скопировав библиотеку smtplib под новым именем в директорию. Там строчку:

self.local_hostname = '[%s]' % addr
Заменил на:
 self.local_hostname = 'localhost'

В принципе, теперь всё работает. Если вдруг кому-то будет не лень, то было бы интересно узнать две вещи:
1)Как это сделать “питонически”?
2)Чем чревато использование локалхоста в ehlo?

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version