简体   繁体   中英

Why do I have to “from module import” with the email module in python?

Sorry if the question isn't spot on, I'm having difficulty phrasing this question properly.

I'm trying to use the email module to create a simple plain text email and send it when certain conditions are met. I'm running in to all sorts of abnormal behavior and would like to understand it. I started with a simple test pulled from the official examples ( https://docs.python.org/3.4/library/email-examples.html ) and it worked fine. When I started trying to implement this in my project I started getting all sorts of "'module' object has no attribute 'something'" . I can run something like this and it works fine

import email
import smtplib

# Create message object
msg = email.message.EmailMessage()

# Create the from and to Addresses
from_address = email.headerregistry.Address("Stack of Pancakes", "pancakes@gmail.com") 
to_address = email.headerregistry.Address("Joe", "pythontest@mailinator.com")

# Create email headers
msg['Subject'] = "subject of email"
msg['From'] = from_address
msg['To'] = to_address

#
email_content = "This is a plain text email"
msg.set_content(email_content)

server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login("pancakes@gmail.com", "password")
server.send_message(msg)
server.quit()

This works perfectly. However if I order things differently things start breaking and I don't understand why. For example if I place the from_address and to_address lines above where the EmailMessage is called like so

import email
import smtplib

# Create the from and to Addresses
from_address = email.headerregistry.Address("Stack of Pancakes", "pancakes@gmail.com") 
to_address = email.headerregistry.Address("Joe", "pythontest@mailinator.com")

# Create message object
msg = email.message.EmailMessage()

... other code

It fails with 'module' object has no attribute 'headerregistry' . Why does the EmailMessage creation allow the other code to function properly?

In fact if I have a file that contains only this

import email

to_address = email.headerregistry.Address("joe", "joe@joe.com")

it fails with the same error.

To get that small snippet to run I had to do this

from email.headerregistry import Address

to_address = Address("joe", "joe@joe.com")

Alternatively, and this is really weird, I can get this to run

import email
import smtplib

email.message.EmailMessage()
to_address = email.headerregistry.Address("joe", "joe@joe.com")

but if I remove the import smtplib it starts failing again, even though I haven't used anything in smtplib in those 4 lines.


I'm fairly certain I can just keep trying every combination I can think of and get it to work properly, but I'd prefer to understand the behavior. That way I would feel more confident running the code in a production environment.

Why can't I just call import email and declare my objects with email.headderregistry.Address , why do I have to explicitly import that specific function with from email.headerregistry import Address ? Why did it compile with import smtplib but failed without it. Why does it work only after EmailMessage() is called?

Normally I'm really good about finding answers, but I think in this situation I just don't know what to search for. There are a whole bunch of solutions to the "module object has no attribute", but most of them were duplicate named files, circular imports, calling functions that didn't exist or checking if an attribute exists. None of them seemed to address how import behavior worked. Am I structuring the code wrong or is the email module just acting up on me?

import email will not automatically import all the modules inside the email package. This means that, in order to use email.headerregistry , you must import it, which can be as simple as:

import email.headerregistry

After that you'll be able to use email.headerregistry.Address .

Your code also works after writing from email.headerregistry import Address because that statement internally does the (equivalent of) import email.headerregistry in order to load the module and get hold of Address . Likewise, smtplib imports email -related modules, some of which likely imports email.headerregistry .

To summarize: once any module performs the import of email.headerregistry , that submodule becomes visible to all modules that imported email , even if they never explicitly requested email.headerregistry . The fact that importing a module can make submodules of an unrelated package available as a side effect can lead to nasty bugs where a module works only if imported after some other modules. Fortunately, modern tools like pylint and Eclipse's pydev are good at fixing this kind of pitfall.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM