0

with Flask I'm sending out emails with an xml and pdf attached. Before the mail is sent I'd like to have a preview of the pdf available, so that the user can check the data.

The pdf is constructed from the xml with the PDFOrder function. The PDF is stored in the variable 'pdf'. So, my question is how can I generate the pdf in memory and make it available as a preview for the user?

Here is the sample code of the outgoing email:

def send_mail():
    Email1 = session.get('Email1')
    Email2 = session.get('Email2')
    invno = session.get('invno')
    username = session['username']
    invId = session['invId']
    xmlStr,xmlFile = XmlGenerator(invId)

try:
    msg = Message(Hi,
    sender="somemail@gmail.com",
    recipients=[Email1,Email2])

    msg.body = '\nHi'

    myxmlinv = xml.dom.minidom.parseString(xmlStr)
    xmlStr = myxmlinv.toprettyxml(encoding="utf-8")
    msg.attach("Test+".xml","application/xml",xmlStr)

    buff = BytesIO()


    pdfdoc = SimpleDocTemplate(buff, pagesize = letter)

    frame = Frame(pdfdoc.leftMargin,
            pdfdoc.bottomMargin,
            pdfdoc.width,
            pdfdoc.height,
            id = 'normal')

    template = PageTemplate(id = 'test', frames = frame)

    pdfdoc.addPageTemplates(template)

    pdforder = PDFOrder(xmlStr)
    Document = pdforder.createPDF()

    pdfdoc.build(Document)

    pdf = buff.getvalue()

    buff.close()

    msg.attach("Test_"+str(invId)+".pdf", "application/pdf", str(pdf))                  
    mail.send(msg)

except Exception, e:
    return(str(e))

The code below takes the user to /preview which should open the pdf. I'd prefer to have the pdf stored in memory. How would I have to render it in HTML?

<a href="/preview" target="_blank"><center><button type=button class="btn btn-default btn-lg">

Thanks!

UPDATE I've managed to save the pdf. But unfortunately it only holds some test of reportlab, although it's got .pdf extension. So, homehow doesnt render in to pdf. Any idea? It strange as the email sending works perfectly with both xml and pdf. You think this part is important: "application/pdf", str(pdf) enter image description here That's my updated definition

@app.route('/preview/')
def preview():
invId = session['invId']
xmlStr,xmlFile = XmlGenerator(invId)

try:
    myxmlinv = xml.dom.minidom.parseString(xmlStr)
    xmlStr = myxmlinv.toprettyxml(encoding="utf-8")

pdfdoc = SimpleDocTemplate("/var/www/FlaskApp/FlaskApp/static/mypdf.pdf", pagesize = letter)
pdforder = PDFOrder(xmlStr)
Document = pdforder.createPDF()
pdfdoc.build(Document)

except Exception, e:
    return(str(e))

return render_template("test.html")
Mark Wellings
  • 71
  • 1
  • 9
  • I'm not sure that you can just display a full pdf from memory. You may have to save it somewhere first then open it like normal. – Joe Jul 01 '17 at 13:09
  • Ok, fair enough. Also, possible to save it to some directory, no big deal. – Mark Wellings Jul 01 '17 at 13:12
  • Yea stand by. I just did this recently. Let me grab the code and Ill post it as an answer – Joe Jul 01 '17 at 13:18
  • Maybe I misread your comment. Were you asking how to save it to a directory – Joe Jul 01 '17 at 13:24
  • Jeah that should do the trick. Save the pdf to a directory and then in the preview page I'll render it somehow. Have to also remove it at some point, os.remove should help. Any other solution which leads to a preview is fine as well. – Mark Wellings Jul 01 '17 at 13:27
  • Yea I did something similar. You can create a `temp` folder then either have your program wipe that folder out as the program is closed or maybe when it launches it will. PDFs are so small it really shouldn't matter – Joe Jul 01 '17 at 13:30
  • any code suggestions would be helpful, I can't get it to work. – Mark Wellings Jul 01 '17 at 13:32
  • yea sorry looking for it now. I cant find the one I built it has been a few weeks. I may have trashed the backups. I will try and slap something together give me a min – Joe Jul 01 '17 at 13:34
  • What I would do is maybe use the `getcwd()` function in conjunction with the `chdir()`. Basically use getcwd as a test and if you are not where you want to be, chdir to your tmp file and then execute the code to launch your pdf. Go to this link to see how to open files with python so they launch with the default system program. https://stackoverflow.com/questions/434597/open-document-with-default-application-in-python – Joe Jul 01 '17 at 13:44

1 Answers1

1

As far as I can tell you are not actually naming your PDF file. This would be done in the simpledoc declaration. Here is an example of one that I have done: doc = SimpleDocTemplate(filename, pagesize=letter) In this situation the filename variable is the full path to where I want the pdf. example: filename = r'C:\User\joe\Desktop\some_file.pdf'`

If you want the file to go into the same directory that you are using you can just give it a name without the full path. ie: filename = 'some_file.pdf'

Once your code hits the doc.build line it will create the pdf.

To open it up use one of these lines:

For MACs:

os.system("open " + filename)

Windows:

os.system("start " + filename)

Joe
  • 2,641
  • 5
  • 22
  • 43
  • Maybe my problem description is a bit weak. I'm actually just trying to save the pdf generated and make it available for the user to preview the pdf. If that's not possible in memory, it's OK to save it in a directory. I haven't manage to save the pdf to a directory from the sample code. – Mark Wellings Jul 01 '17 at 13:49
  • Yea the sample code was more for choosing directory. Let me look again and see what i can come up with. I think I see now what you want – Joe Jul 01 '17 at 14:02
  • pdfdoc = SimpleDocTemplate(buff, pagesize = letter) is naming the file as 'buff' I reckon. Could I ask you to post the entire code based on the update above? – Mark Wellings Jul 01 '17 at 15:11
  • I extended this guys code for my pdf app. The app I just finished building queries a db converts the results to pdf and saves them to said directory. I also build an automated version that runs automatically and emails the results to my clients. Here is the link to the pdf tutorial. This code may take some modification but works great. [Calazan](https://www.calazan.com/a-simple-python-program-for-exporting-a-list-of-dictionaries-to-a-pdf-table-using-reportlab/) – Joe Jul 01 '17 at 15:34
  • I see that you have buff there but I am not sure what buff is returning. Is your system creating any file? You may have to change whats in buff – Joe Jul 01 '17 at 15:35
  • It does generate the file for the email, but doesnt save the pdf in the preview url – Mark Wellings Jul 02 '17 at 09:35
  • what do you mean by preview url – Joe Jul 02 '17 at 12:08
  • See the updated post, there is a /preview page which should render the PDF. – Mark Wellings Jul 02 '17 at 13:18
  • Any idea? Actually it seems way more complicated what I'm doing with the email. Still haven't figured out how to save the pdf – Mark Wellings Jul 03 '17 at 11:07
  • Are you giving the file a .pdf extension – Joe Jul 03 '17 at 20:51
  • Thanks mate for the help. When attaching it to the mail yes: `msg.attach("Test_"+str(invId)+".pdf", "application/pdf", str(pdf))`, but when trying to créate the preview no.. how would i do that? – Mark Wellings Jul 05 '17 at 08:33
  • It needs to happen when naming / saving it. So I would append it to your `buff` variable. Maybe like this - `buff = buff + '.pdf'` – Joe Jul 05 '17 at 16:52
  • Thanks for your efforts but I still cant get it to work. I'm under the impression that buff is only used to attach the pdf to the email, so maybe I'm overcomplicating. I think I'll try to add to the PDFORDER function some filesaving with reportlab. – Mark Wellings Jul 06 '17 at 19:12
  • I think you are over thinking it. I dont know why you think buff is attaching to the email but i'm pretty sure that is not what it is doing. Try replacing buff with something like `test.pdf` to see if it saves in your project directory with that – Joe Jul 06 '17 at 20:53
  • I've managed to save a file with the pdf extension but it rendered in a strange way. Please, see update. – Mark Wellings Jul 08 '17 at 15:39