10

I am trying to generate emails using the standard email library and save them as .eml files. I must not be understanding how email.generator works because I keep getting the error 'AttributeError: 'str' object has no attribute 'write.'

from email import generator
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
active_dir = 'c:\\'

class Gen_Emails(object):
    def __init__(self):
        self.EmailGen()

    def EmailGen(self):
        sender = 'sender'
        recepiant = 'recipiant'
        subject = 'subject'

        msg = MIMEMultipart('alternative')
        msg['Subject'] = subject
        msg['From'] = sender
        msg['To'] = recepiant


        html = """\
        <html>
            <head></head>
            <body>
                <p> hello world </p>
            </body>
        </html>
        """
        part = MIMEText(html, 'html')

        msg.attach(part)

        self.SaveToFile(msg)

    def SaveToFile(self,msg):
        out_file = active_dir
        gen = generator.Generator(out_file)
        gen.flatten(msg)

Any ideas?

user3434523
  • 178
  • 1
  • 2
  • 9

2 Answers2

9

You are supposed to pass an open file (in write mode) to Generator(). Currently you pass it just a string, which is why it fails when it tries to call .write() on the string.

So do something like this:

import os
cwd = os.getcwd()
outfile_name = os.path.join(cwd, 'message.eml')

class Gen_Emails(object):    

    # ...

    def SaveToFile(self,msg):
        with open(outfile_name, 'w') as outfile:
            gen = generator.Generator(outfile)
            gen.flatten(msg)

Note: with open(outfile_name, 'w') as outfile opens the file at the path outfile_name in write mode and assigns the file pointer to the open file to outfile. The context manager also takes care of closing the file for you after you exit the with block.

os.path.join() will join paths in a cross-plattform way, which is why you should prefer it over concatenating paths by hand.

os.getcwd() will return your current working directory. If you want to your file to be saved somewhere else just change it out accordingly.

Lukas Graf
  • 30,317
  • 8
  • 77
  • 92
8

Here is a modified solution that works with extra headers too. (This was tested with Python 2.6)

import os
from email import generator
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

html_data = ...

msg = MIMEMultipart('alternative')
msg['Subject'] = ...
msg['From'] = ...
msg['To'] = ...
msg['Cc'] = ...
msg['Bcc'] = ...
headers = ... dict of header key / value pairs ...
for key in headers:
    value = headers[key]
    if value and not isinstance(value, basestring):
        value = str(value)
    msg[key] = value

part = MIMEText(html_data, 'html')
msg.attach(part)

outfile_name = os.path.join("/", "temp", "email_sample.eml")
with open(outfile_name, 'w') as outfile:
    gen = generator.Generator(outfile)
    gen.flatten(msg)

print "=========== DONE ============"
Ajay Gautam
  • 997
  • 12
  • 14