Home > front end >  AttributeError: 'str' object has no attribute 'get_all'
AttributeError: 'str' object has no attribute 'get_all'

Time:04-16

I'm making a function in Python that sends email with the attachment being optional. However, when I try to send a file, it gives the error "AttributeError: 'str' object has no attribute 'get_all'".

I looked at other Stack Overflow posts and other sites for help. I took all their advice and yet, I'm still getting the same error. What can I try next?

Full error:

Traceback (most recent call last):
  File "/Users/XXX/Desktop/device_control_virus/emailing.py", line 65, in <module>
    email("testing", "testing testing", "[email protected]", "logs.txt")
  File "/Users/XXX/Desktop/device_control_virus/emailing.py", line 60, in email
    s.send_message(text)
  File "/Users/XXX/opt/anaconda3/lib/python3.8/smtplib.py", line 926, in send_message
    resent = msg.get_all('Resent-Date')
AttributeError: 'str' object has no attribute 'get_all'

Here's the code:

from email import message
import smtplib
from email.message import EmailMessage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from email.message import EmailMessage

def email(subject, body, to, attachment=None):

    if attachment == None:
        msg = EmailMessage()
        msg.set_content(body)
        msg['subject'] = subject
        msg['to'] = to

        user = "[email protected]"
        msg['from'] = user
        password = "XXXXXXXXX"

        s = smtplib.SMTP("smtp.gmail.com", 587)
        s.ehlo()
        s.starttls()

        s.login(user, password)

        s.send_message(msg)

        s.quit()

    else:
        msg = MIMEMultipart()
        msg['subject'] = subject
        msg['to'] = ', '.join(to)

        user = "[email protected]"
        msg['from'] = user
        password = "XXXXXXXXX"

        msg.attach(MIMEText(body, 'plain'))

        filename = attachment
        attachment = open(filename, "rb")

        part = MIMEBase('application', 'octet-stream')
        part.set_payload((attachment).read())
        encoders.encode_base64(part)
        part.add_header('Content-Disposition', "attachment; filename= %s" % filename)

        msg.attach(part)

        s = smtplib.SMTP("smtp.gmail.com", 587)
        s.ehlo()
        s.starttls()

        s.login(user, password)

        text = msg.as_string()

        s.send_message(text)

        s.quit()

if __name__ == '__main__':
    email("testing", "testing testing", "XXXXXXXXX", "logs.txt")

CodePudding user response:

The problem is that you are passing a string to send_message, but it expects a Message object. You should be able to fix your problem by changing this:

text = msg.as_string()

s.send_message(text)

To this:

s.send_message(msg)

Edit

I think your "503 5.5.1 RCPT first" problem may be due to the to field in your message. You are using the code msg['to'] = ', '.join(to), which expects a list of email addresses. However, when you call it, you are passing in the single string "XXXXXXXXX".

When you call join with a string, it joins together all the characters, as in Python you can iterate through a string by character. This means ', '.join("XXXXXXXXX") will give you the string X, X, X, X, X, X, X, X, X, i.e. a list of characters in your email address, instead of the single email address you were probably expecting. Instead, try setting the to field like msg['to'] = to.

CodePudding user response:

Your code rather horribly mixes the modern EmailMessage API with the legacy MIMEMultipart etc email classes from Python pre 3.6. The new API is much simpler and more versatile, and you should simply not use the old unless you specifically need to support Python 3.2 or older (the new API was introduced but not yet preferred in 3.3).

I haven't attempted to debug your code in detail; I would recommend that you simply ditch it and start over, then troubleshoot whatever new problems you may encounter.

from email.message import EmailMessage  # just once should suffice
import smtplib

def email(subject, body, to, attachment=None):

    msg = EmailMessage()
    msg.set_content(body)
    msg['subject'] = subject
    msg['to'] = to

    user = "[email protected]"
    msg['from'] = user
    password = "XXXXXXXXX"

    if attachment is not None:
        with open(attachment, 'rb') as fp:
            msg.add_attachment(
                fp.read(),
                maintype='attachment',
                subtype='octet-stream',
                filename=attachment)

    with smtplib.SMTP("smtp.gmail.com", 587) as s:
        s.ehlo()
        s.starttls()
        s.login(user, password)
        s.send_message(msg)
        s.quit()

if __name__ == '__main__':
    email("testing", "testing testing", "XXXXXXXXX", "logs.txt")

You would still need to replace the to address with a valid email address, and perhaps verify that the steps and the parameters in the smtplib dialog with Gmail are correct.

(Also, the correct MIME type for a text file would be text/plain; but application/octet-stream is of course always a viable content type, especially if your code needs to handle arbitrary file types.)

  • Related