[Tutor] pdf file as attachment

Harm Kirchhoff harm.kirchhoff at web.de
Wed Aug 25 10:57:24 CEST 2004


I have recently experimented with excel files as attachments.
I think the code should work for pdf files, too.

I attach some sample code. This sample mails all files in the direcotry
defined as path. Be careful to thest this on .pdf files, because you can
see that I used in-memory storage by constructing my own buffer.

Don't do this for larger files. The below is experimental code which I
used to understand the concept.

Further down I attach the code that I am actually using to get my work done.

I hope this helps.



#############################################################################3
#!/usr/bin/env/ python


"""
This example was tested and worked just fine.
"""
import base64, quopri
import mimetypes, email.Generator, email.Message
import cStringIO, os

toAddr   =
"harm_kirchhoff at mail.digital.co.jp,hk at pop.ms,harm.kirchhoff at r8.dion.ne.jp"
fromAddr = "harm_kirchhoff at mail.digital.co.jp"

outputFile = 'mailmessage.tmp'

def main():
    print 'start main'
    mainMsg                  = email.Message.Message()
    mainMsg["To"]            = toAddr
    mainMsg["From"]          = fromAddr
    mainMsg["Subject"]       = "files"
    mainMsg["Mime-version"]  = "1.0"
    mainMsg["Content-type"]  = "Multipart/mixed"
    mainMsg.preamble         = "Mime message\m"
    mainMsg.epilogue         = ""

    path = "C:/Program Files/Zope262/Extensions/cost_mailer/templates"

    fileNames = [f for f in os.listdir(path)] # if os.path.isfile(f) ]
    print 'List of files:',fileNames
    for fileName in fileNames:
        fileName = path + '/' + fileName
        contentType,ignored = mimetypes.guess_type(fileName)
        if contentType == None: # If no guess, use generic opaque text
            contentType = "application/octet-stream"
        contentsEncoded = cStringIO.StringIO()
        f = open(fileName,"rb")
        mainType = contentType[:contentType.find("/")]
        if mainType == "text":
            cte = "quoted-printable"
            quopri.encode(f, contentsEncoded, 1) # 1 to encode tabs
        else:
            cte = "base64"
            base64.encode(f, contentsEncoded)
        f.close()

        subMsg = email.Message.Message()
        subMsg.add_header( "Content-type", contentType, name=fileName)
        subMsg.add_header( "Content-transfer-encoding", cte)
        subMsg.add_payload(contentsEncoded.getvalue() )
        contentsEncoded.close()
        mainMsg.add_payload(subMsg)

    subMsg = email.Message.Message()
    subMsg.add_header( "Content-type", "text")
    subMsg.add_header( "Content-transfer-encoding", "quoted-printable")
    subMsg.add_payload('This is a plain us-ascii message string' )
    contentsEncoded.close()
    mainMsg.add_payload(subMsg)


    #f = open(outputFile, "wb")
    f = temp_buffer()
    g = email.Generator.Generator(f)
    g(mainMsg)
    f.close()

    print "done, now sending"
    import smtplib
    #f = open(outputFile, "rb")
    s = f.read()

    server = smtplib.SMTP('smtp.server.com',0)  # server and port
    server.sendmail(fromAddr,toAddr,s)


    return True

class temp_buffer:
    """
    email.Generator.Generator() requires an output file as argument,
    or another storage object that supports write methods.
    Writing to files is adequate for larger messages, but keeping the
    process in the buffer is better when the messages are to be sent
    immediately and now large memmory is consumed.
    """

    def __init__(self):
        self.contents = ""

    def write(self,var):
        self.contents = self.contents + var

    def read(self):
        return self.contents

    def close(self):
        "Just to be compliant with files"
        return True

if __name__ == '__main__':
    #   If run as stand alone ...
    main()


###########################################################################
"""
Here you see the loop that I use in my actual program to compile and
send the emails. This is only an exerpt
"""
                for toAddr in self.init.recipients[report]:
                    # email header
                    mainMsg                  = email.Message.Message()
                    mainMsg["To"]            = toAddr
                    mainMsg["From"]          = self.init.notify
                    mainMsg["Subject"]       = self.init.header+report
                    mainMsg["Mime-version"]  = "1.0"
                    mainMsg["Content-type"]  = "Multipart/mixed"
                    mainMsg.preamble         = "Mime message\m"
                    mainMsg.epilogue         = ""
                    # First lines of message
                    try:
                        header.write('Report for Cost Center: '+report +
', '+Date+'\n\n')
                        header.write('All amounts in JPY.\n\n')
                        subMsg = email.Message.Message()
                        subMsg.add_header( "Content-type", "text")
                        subMsg.add_header( "Content-transfer-encoding",
"quoted-printable")
                        contentsEncoded = cStringIO.StringIO()
                        quopri.encode(header, contentsEncoded, 1) # 1 to
encode tabs
                        subMsg.add_payload( contentsEncoded.getvalue() )
                        contentsEncoded.close()
                        header.close()
                        mainMsg.add_payload(subMsg)
                    except:
                        self.init.gui.write('Failed to include header
into email.')
                    # report.csv file part of the message
                    subMsg = email.Message.Message()
                    subMsg.add_header( "Content-type",
"application/octet-stream", name='report.csv')
                    subMsg.add_header( "Content-transfer-encoding",
"base64")
                    contentsEncoded = cStringIO.StringIO()
                    buff     = file( repFile, 'rb')
                    base64.encode(buff, contentsEncoded)
                    buff.close()
                    subMsg.add_payload( contentsEncoded.getvalue() )
                    contentsEncoded.close()
                    mainMsg.add_payload(subMsg)
                    # ledger.csv file part of the message
                    subMsg = email.Message.Message()
                    subMsg.add_header( "Content-type",
"application/octet-stream", name='ledger.csv')
                    subMsg.add_header( "Content-transfer-encoding",
"base64")
                    contentsEncoded = cStringIO.StringIO()
                    buff     = file( csvFile, 'rb')
                    base64.encode(buff, contentsEncoded)
                    buff.close()
                    subMsg.add_payload( contentsEncoded.getvalue() )
                    contentsEncoded.close()
                    mainMsg.add_payload(subMsg)
                    # last lines of message
                    try:
                        subMsg = email.Message.Message()
                        subMsg.add_header( "Content-type", "text")
                        subMsg.add_header( "Content-transfer-encoding",
"quoted-printable")
                        contentsEncoded = cStringIO.StringIO()
                        header.write( '\n\n'+self.init.footer)
                        quopri.encode(header, contentsEncoded, 1) # 1 to
encode tabs
                        subMsg.add_payload( contentsEncoded.getvalue() )
                        contentsEncoded.close()
                        header.close()
                        mainMsg.add_payload(subMsg)
                    except:
                        self.init.gui.write('Failed to include footer
into email.')
                    # and send it:
                    f = open(emlFile, "wb")
                    g = email.Generator.Generator(f)
                    g(mainMsg)
                    f.close()
                    f = open(emlFile, "rb")
                    s = f.read()
                    f.close()
                    error =
mail_man(self.init.notify,toAddr,s,self.init.SMTPserver,0)
                    del s,f
                    if error <> True:
                        if error == -1:
                            self.init.gui.write('Report_Mailer failed to
initialize SMTP server. Settings wrong ?')
                            self.init.gui.write('
Server:'+self.init.SMTPserver                         )
                            self.init.gui.write('  Port
:'+str(self.init.port)                          )
                            return False
                        else:
                            self.init.gui.write('Failed to send mails
to:'+self.init.notify)
                            self.init.gui.write('A possible reason may
be that you use Japanese characters.')
                            for index in error:
                                self.init.gui.write( mail_list[index][1] )
                                return False
##########################################################
"""
And here is the routine that actually sends the email.
"""
def mail_man(fromAddr, toAddr, Message, Server, Port):
    """Sends mails from a list.

    Message :   A mail message (correctly encoded)
    Server  :   A string with the server address
    Port    :   An integer with the port number

    Returns:
        True    If all mails sent
        -1      If Server could not be initialized
        0 ...   A list of numbers x that correspond to the elements in
Mails[x],
                describing the message that could not be sent.
    """
    # Open the server
    import smtplib
    error = True
    try:
        server = smtplib.SMTP(Server, Port)
    except:
        return -1
    # send message
    try:
        server.sendmail( fromAddr, toAddr , Message )
    except:
        error = False

    # close server
    if error == True:
        server.quit()
        return True
    else:
        return -2




More information about the Tutor mailing list