MimeWriter and PDFs

Steve Holden sholden at holdenweb.com
Fri May 2 08:47:47 EDT 2003


"Brandon" <berklee at hotmail.com> wrote ...
> Hoping I can get a little help here...
>
Let's see. We may or may not need a bit more information, but seeing real
code is encouraging.

> I've got a global nested list of recipients, each containing a file
> name and an e-mail address. The process that generates the PDFs has no
> problem - I'm saving them to the hard drive, and opening them seems to
> not be a problem.
>
In other words, it appears the PDf file integrity is good after you've
created
them. I hope you're doing that in Python too ...

> However, once I attach the PDF and send it, I try to open the attached
> file and get the following message from Acrobat:
>
> "There was an error opening this document. The file is damaged and
> could not be repaired."
>
This is when, for example, you double-click the received attachment in your
mail reader tool?

> I've opened the PDF in a text viewer (the same PDF, before and after
> sending it), and it appears that the one that's been sent out has a
> bunch of extra data on the end of it.
>
Does this definitely mean that the contents up to the length of the
transmitted file are definitely equalr, or just "I saw some extra stuff at
the end,, but I don't know exactly how much or what"?

> Anyone? Anyone? Bueller? :)
>
> Thanks,
> B.
>
Please note that the email module is to be preferred for this and similar
applications. Being of more recent design it has a rather more pleasant
interface. Since it's being used in MailMan it's presumably also handled a
*lot* of messages without falling over too badly, it can contruct messages
by parsing as well as using constructive methods, etc., etc., etc.

More of that later, however. For now, you've got code that uses MimeWriter.
OK.

> def shipEMail():
>     """
>     Sends MIME-Type e-mails with attached PDFs, and deletes them
> afterwards.
>     """
>     fName = "75day.pdf"
>     for eMail in recipients:
>         # We are using a string as a temporary file
>         outputfp = StringIO.StringIO()
>         w = MimeWriter.MimeWriter(outputfp)
>         w.addheader("subject", "Report")
>         w.addheader("MIME-Version", "1.0")

It would be a really good idea to add a "To:" header here, and I have come
across mailers that require, for example, a "Date:" and/or a "Message-Id:"
header, although an accommodating mail host will usually add these last two.

>         w.flushheaders()

not required, see below

>         w.startmultipartbody("mixed")
>         instructions = w.nextpart()
>         instFile = instructions.startbody("text/plain")
>         instructions.flushheaders()
>         instFile.write("""
> Please see the attached PDF file.
> """)
>         subwriter = w.nextpart()
>         subwriter.addheader("Content-Transfer-Encoding", "base64")
>         subwriter.addheader("Content-Disposition", 'attachment;
> filename="%s"' % fName)
>         f = subwriter.startbody('application/octet-stream; name="%s"'
> % fName)
>         #f = subwriter.startbody('application/pdf; name="%s"' % fName)
>         subwriter.flushheaders()

>         base64.encode(open('%s' % eMail[1], 'r'), f)

I would recommend you open that file in binary mode ('rb'). This may well be
responsible for your problem. In Windows systems you're just thrown away all
the carriage returns in your file. If those carriage returns aren't really
ASCII characters, but instead a part of carefully-crafted binary data,
whoops.

>         w.lastpart()

On page 151 and 152 of "Python Web Programming" (in the code for
"multiwrite.py") I create a message this way:

    mail = MimeWriter.MimeWriter(f) # the file isn't important
    mail.addheader(...) ...
    part1 = mail.startmultipartbody("mixed")
    part1.write("This is a MIME-encoded message ...")
    part2 = mail.nextpart()
    f = part.startbody("text/plain")
    f.write("Here is the enormous file you asked for")
    part3 = mail.nextpart()
    part3.addheader("Content-Transfer-Encoding", "base64")
    f.write( ... )
    mail.lastpart()

In other words, you call startmultipartbody() to get the body, and into that
you write a cover letter that will be seen by readers using non-MIME-capable
tools.

You then call nextpart() to get successive parts, into which you write
approriate content. Each part appears as an appropriate object in a
MIME-capable reader (MTA). The book's next page depicts both the text and
the graphic (but *not* the part1 content) in an Outlook Express window.
Finally, as you spotted, you call lastpart() after the last one. I don't
think the flushheaders() calls are required, simply available for authors of
apps that use mail-like data formats with no bodies.

>         try:
>             server = smtplib.SMTP(mailServer)
>             result = server.sendmail("someguy at somedomain.com",
> eMail[0], outputfp.getvalue())
>             server.quit()
>             if result:
>                 for r in result.keys():
>                     print "Error sending to ", r
>                     rt = result[r]
>                     print "Code : ", rt[0], ":", rt[1]
>             else:
>                 print "Sent to " + eMail[0] + " successfully."
>         except (smtplib.SMTPException, socket.error), arg:
>             print "SMTP Server could not send mail", arg

The SMTP side seems sane enough to require no further comment.

Regarding the email module: there's probably enough code using that noe that
you could rewrite your example using email in less than twenty minutes.
However, I'd encourage you to fix up your current example using MimeWriter
just so you know it can work :-)

Python Web Programming was an attempt to put slightly better examples to fit
with the documentation for what is actually a lot of very funky stuff. The
fact that we now have even better stuff doesn't make the old stuff less
funky, just not quite so cool ...

regards
--
Steve Holden                                  http://www.holdenweb.com/
Python Web Programming                 http://pydish.holdenweb.com/pwp/







More information about the Python-list mailing list