views:

1294

answers:

4
+3  Q: 

Python 3.0 smtplib

I have a very simple piece of code that I used in previous versions of Python without issues (version 2.5 and prior). Now with 3.0, the following code give the error on the login line "argument 1 must be string or buffer, not str".

import smtplib

   smtpserver = 'mail.somedomain.com'
   AUTHREQUIRED = 1                     # if you need to use SMTP AUTH set to 1
   smtpuser = '[email protected]'    # for SMTP AUTH, set SMTP username here
   smtppass = 'somepassword'            # for SMTP AUTH, set SMTP password here
   msg = "Some message to send"

   RECIPIENTS = ['[email protected]']
   SENDER = '[email protected]'

   session = smtplib.SMTP(smtpserver)

   if AUTHREQUIRED:
      session.login(smtpuser, smtppass)

   smtpresult = session.sendmail(SENDER, RECIPIENTS, msg)

Google shows there are some issues with that error not being clear, but I still can't figure out what I need to try to make it work. Suggestions included defining the username as b"username", but that doesn't seem to work either.

+3  A: 
Traceback (most recent call last):
  File "smtptest.py", line 18, in <module>
    session.login(smtpuser, smtppass)
  File "c:\Python30\lib\smtplib.py", line 580, in login
    AUTH_PLAIN + " " + encode_plain(user, password))
  File "c:\Python30\lib\smtplib.py", line 545, in encode_plain
    return encode_base64("\0%s\0%s" % (user, password))
  File "c:\Python30\lib\email\base64mime.py", line 96, in body_encode
    enc = b2a_base64(s[i:i + max_unencoded]).decode("ascii")
TypeError: b2a_base64() argument 1 must be bytes or buffer, not str

Your code is correct. This is a bug in smtplib or in the base64mime.py. You can track the issue here: http://bugs.python.org/issue5259

Hopefully the devs will post a patch soon.

Richard J. Terrell
beat me to it :-) It looks like there's more than just this issue present in trying to use Python 3.0 with smtplib because even after patching base64mime.py error responses are returned from the mail server when they shouldn't be, as far a I can tell.
Jay
stupid me for not checking the bug tracker link, the posted suggest change to encode_plain() works just fine with a couple small changes to smtplib.py
Jay
"must be bytes or buffer, not str" is a bug found in many locations in the standard library, unfortunately.
Evan Fosmark
+3  A: 

UPDATE: just noticed from a look at the bug tracker there's a suggested fix also:

Edit smtplib.py and replace the existing encode_plain() definition with this:

def encode_plain(user, password):
    s = "\0%s\0%s" % (user, password)
    return encode_base64(s.encode('ascii'), eol='')

Tested here on my installation and it works properly.

Jay
+1  A: 

As a variation on Jay's answer, rather than edit smtplib.py you could "monkey patch" it at run time.

Put this somewhere in your code:


def encode_plain(user, password):
    s = "\0%s\0%s" % (user, password)
    return encode_base64(s.encode('ascii'), eol='')

import smtplib
encode_plain.func_globals = vars(smtplib)
smtplib.encode_plain = encode_plain

This is kind of ugly but useful if you want to deploy your code onto other systems without making changes to their python libraries.

Greg Ball
A: 

This issue has been addressed in Python3.1. Get the update at http://www.python.org/download/releases/3.1/

ali01