Thursday, September 2, 2010
  • Index
  •  » Code Exchange
  •  » Automatically print out incoming eMails and attachments in Apple Mail

#1 2008-06-16 06:09:35 am

Martin Michel
Administrator
From: Berlin, Germany
Registered: 2008-03-03
Posts: 655
Website

Automatically print out incoming eMails and attachments in Apple Mail

I was often asked, if I could provide a simple solution to print out incoming eMails and attachments in Apple Mail. Well, so far I couldn't, as Apple Mail unfortunately doesn't support to automatically print documents without invoking the print dialog.

But then my employer also needed such a solution in order to automatically process incoming work orders and print their PDF attachments to a network printer in the production hall. And so I had to take a closer look at how to automatically print eMails and attachments in Apple Mail. After happily spending an entire morning in front of my office iMac, I am proud to share my little AppleScript snippet with you. May it also make your future workdays a little bit easier:



An eMail message printed out by pergamail might look like that:

http://files.macscripter.net/joy/images/pergamailsample.jpg


Requirements
pergamail was tested under/with:
• Mac OS X 10.5.1
• Apple Mail 3.1
• Intel & PowerPC based Macs

Installation
To install pergamail on your Mac, you must first download it and then create a custom mail rule in Apple Mail. In this mail rule you have to choose to run an AppleScript as shown below:

 - Click to enlarge


All rule-matching eMails will then be processed by pergamail and - hopefully - printed out accordingly.

Configuration
pergamail offers some advanced options, which you can directly set in its source code. Just open the script in the Script Editor and have a look at the first lines. When making changes to pergamail, please always save it as a «Script bundle», as it also contains a little Python script, which translates byte sizes into a human readable form.

«defprintapp»

Applescript:


property defprintapp : "TextEdit"
-- default value: "TextEdit"
-- possible values: "lpr" or "TextEdit"

You can set defprintapp to print either via the shell using the «lpr»-command or via TextEdit, which can also automatically print documents using AppleScript without invoking the print dialog. If TextEdit was not running on your Mac at the time pergamail started its work, it will quit it afterwards.

«defprintername»

Applescript:


property defprintername : missing value
-- default value: missing value
-- possible values: any name of an available printer, e.g. "HP LaserJet 1300"

By default, pergamail is printing to the currently set printer. But if you always want to print to a specific printer, just provide the printer name here. After pergamail is finished, it will always set back your printer to the one used before.

«defprintatms»

Applescript:


property defprintatms : false
-- default value: false
-- possible values: false or true

If you want to try to also print out the attachments of the eMail messages, then set this value to true. But please note that pergamail can only print attachments, which can be printed out using the «lpr»-command (PS, PDF, RTF(D), TXT, HTML, most image formats natively supported by Mac OS X).

«defmsginfo»

Applescript:


property defmsginfo : "short"
-- default value: "short"
-- possible values: "short" or "long"

If you set this property to "long", some more infos will show up in the mail header, e.g. message size.

Notes
Please note, that pergamail currently doesn't support fancy HTML eMail very good. You won't see any pictures or formatted text in the printouts from pergamail. Maybe this can be overcome in the future by parsing the raw source of the eMail messages with a Python/Ruby/Perl script, then extracting and saving the HTML part, and finally printing it with the «lpr»-command. Maybe.

Moreover I encountered some problems, when I tried to use pergamail with my Bonjour-shared HP network printer at home. But it runs just fine in the company. So if you encounter any problems, please remember that pergamail is currently just a little beta script. It's not an expensive and mature application.

Important: If pergamail encounters an error, it creates a log file named «pergamail.log» on your desktop containing the last error message.

With a little bit of AppleScript knowledge (maybe even without) you can easily adjust the pergamail eMail output to your own requirements. Just look for the «msgtotxt» function.

Future
Currently pergamail creates text files from incoming eMail messages, but it would be much better to directly create HTML or PDF documents to get more control over the print layout. previmail alreday uses an advanced HTML template and Colendar shows hot to create a PDF on the fly, so I might just need to invest another weekend to write an improved version of pergamail big_smile

Last but not least, all parts of pergamail can be inspected with the Script Editor. I invite everybody to modify, enhance and misuse pergamail for their own purposes.

Happy eMail printing!

Important: Opening and saving the below script code in Script Editor won't result in a usable AppleScript! That is because pergamail internally relies on a Python script, which is located inside its Script bundle. Therefor please download the complete script here.

Applescript:


-- created: 05.02.2008

-- Installed together with an AppleScript-based Apple Mail mail rule,
-- this script - hopefully - prints out all rule-matching eMails (and their
-- attachments according to the options manually set below)

-- The script was tested under/with:
-- • Mac OS X 10.5.1
-- • Apple Mail 3.1
-- • Intel & PowerPC based Macs

property mytitle : "pergamail"
property myversion : "0.1b"

-- here you can set the application which is going to
-- print the eMail message: TextEdit or lpr
-- the default value is 'TextEdit'
-- why 'TextEdit'? because it can print without
-- invoking the print dialog
-- lpr is pure printing via the command line
-- possible values: "TextEdit" or "lpr"
property defprintapp : "TextEdit"
-- you can choose a default printer to be used, e.g.
-- "HP LaserJet 1300"
-- default value is missing value
property defprintername : missing value
-- do you also want to try to print the eMail attachments?
-- please note, that you can currently only print
-- attachments of the following types (due to the use of the 'lpr'-command):
-- PDF, RTF(D), TXT, HTML, most image formats natively
-- supported by Mac OS X
property defprintatms : false
-- you can set this property to 'long' to see even more mail infos
-- in the plain text report
property defmsginfo : "short"

-- unique handler to perform AppleScript actions on rule-matching Apple Mail messages
using terms from application "Mail"
   on perform mail action with messages matchmsgs for rule therule
       repeat with matchmsg in matchmsgs
           my printmailmsg(matchmsg)
       end repeat
   end perform mail action with messages
end using terms from

-- deactivated debug routine
(*on run
   tell application "Mail"
       set msg to item 1 of (selection as list)
       my printmailmsg(msg)
   end tell
end run*)


-- main function controlling the script procedure
on printmailmsg(msg)
   try
       -- converting the Apple Mail message to a plain text report
       --set msgtxt to "Hallo"
       set msgtxt to my msgtotext(msg)
       -- finding and getting an unused temp file
       set tmpfilepath to my TmpFile's newpath()
       -- saving the plain text report in the temp file as UTF-8
       my writetofile(msgtxt, tmpfilepath)
       -- printing the temp file
       my printfile(tmpfilepath, defprintapp)
       -- deleting the temp file
       my TmpFile's remove()
       -- printing the attached files if possible
       if defprintatms is true then
           my printatms(msg)
       end if
       -- THE END
   on error errmsg number errnum
       set logmsg to ((current date) as Unicode text) & ": " & errmsg & " (" & errnum & ")"
       set logfile to ((path to desktop) as Unicode text) & "pergamail.log"
       my writetofile(logmsg, logfile)
   end try
end printmailmsg

-- I am printing the given file with the chosen application
on printfile(filepath, printapp)
   -- if the user chose to use a default printer,
   -- we must know the current printer, as we might have
   -- to set it back later
   if defprintername is not missing value then
       set curprintername to my getcurprintername()
       my setcurprinterbyname(defprintername)
   end if
   -- printing via the command line
   if printapp is "lpr" then
       -- silence is golden...
       set cmd to "lpr " & quoted form of (POSIX path of filepath)
       set cmd to cmd as «class utf8»
       do shell script cmd
       -- printing via TextEdit
   else if printapp is "TextEdit" then
       -- if TextEdit is currently not running, we
       -- should quit it afterwards
       if appisrunning("TextEdit") then
           set tewasrunning to true
       else
           set tewasrunning to false
       end if
       -- printing the file without invoking the print dialog and
       -- without bringing TextEdit to the foreground
       tell application "TextEdit"
           set newdoc to open (filepath as alias)
           print newdoc without print dialog
           close newdoc
       end tell
       -- cleaning up...like mother told us
       if not tewasrunning then
           tell application "TextEdit"
               quit
           end tell
       end if
   end if
   -- setting back the default printer to its prior value
   if defprintername is not missing value then
       my setcurprinterbyname(curprintername)
   end if
end printfile

-- I am printing the attachments of a mail message if possible
on printatms(msg)
   -- saving all attachments in temporary files
   set tmpfilepaths to {}
   tell application "Mail"
       set atms to mail attachments of msg
       repeat with atm in atms
           set atmname to name of atm
           repeat
               set rndnum to random number from 1000 to 99999
               set tmpfolder to (path to temporary items folder from user domain) as Unicode text
               set tmpfilepath to tmpfolder & "tmp_" & rndnum & "_" & atmname
               try
                   set tmpfilepath to tmpfilepath as alias
               on error
                   exit repeat
               end try
           end repeat
           try
               save atm in tmpfilepath
               set tmpfilepaths to tmpfilepaths & tmpfilepath
           end try
       end repeat
   end tell
   -- printing the temporarily saved attachments and then deleting them afterwards
   -- not all attachment types can be printed (e.g. MS Word/Exel, etc.)
   repeat with tmpfilepath in tmpfilepaths
       my printfile(tmpfilepath, "lpr")
       tell application "Finder"
           delete (tmpfilepath as alias)
       end tell
   end repeat
end printatms

-- I am returning the name of the current printer
on getcurprintername()
   tell application "Printer Setup Utility"
       return name of current printer
   end tell
end getcurprintername

-- I am setting the current printer to the given printer name
on setcurprinterbyname(printername)
   tell application "Printer Setup Utility"
       set allprinters to every printer
       set printernames to name of every printer
       if printername is not in printernames then
           return false
       else
           if name of current printer is not equal to printername then
               set current printer to printer printername
           end if
           return true
       end if
   end tell
end setcurprinterbyname

-- I am converting an Apple Mail eMail message to a plain text report
on msgtotext(msg)
   set newline to ASCII character 10
   tell application "Mail"
       --set msgid to id of msg
       set msguid to message id of msg
       set msgsize to my getstringsize(message size of msg)
       --set msgmbox to name of mailbox of msg
       set msgcont to content of msg
       set msgsender to sender of msg
       set msgrecvd to date received of msg
       set msgsent to date sent of msg
       set msgsubj to subject of msg
       set msgtorec to my gettxtrecipients("TO", msg)
       set msgccrec to my gettxtrecipients("CC", msg)
       set msgbccrec to my gettxtrecipients("BCC", msg)
       set msgatms to my gettxtatms(mail attachments of msg)
       set msgreplyto to reply to of msg
       --set msgpath to my getmsgpath(msgid)
   end tell
   -- basic report:
   set msgtext to "+ + + + + + + + + + + + + + + + + + + + + + + + + + + +" & newline & newline
   set msgtext to msgtext & "SUBJECT: " & msgsubj & newline & "FROM: " & msgsender & newline & "DATE: " & msgrecvd & newline & "TO: " & msgtorec
   -- further enhancing the report if information is available
   -- >> CC recipients?
   if msgccrec is not missing value then
       set msgtext to msgtext & newline & "CC: " & msgccrec
   end if
   -- >> BCC recipients?
   if msgbccrec is not missing value then
       set msgtext to msgtext & newline & "BCC: " & msgbccrec
   end if
   -- >> long info?
   if defmsginfo is "long" then
       set msgtext to msgtext & newline & "SIZE: " & msgsize & newline & "SENT: " & msgsent & newline & "REPLY-TO: " & msgreplyto
   end if
   -- >> attachments?
   if msgatms is not missing value then
       set msgtext to msgtext & newline & newline & "##########" & newline & msgatms & newline & "##########"
   end if
   set msgtext to msgtext & newline & newline & "+ + + + + + + + + + + + + + + + + + + + + + + + + + + +" & newline & newline & msgcont
   return msgtext
end msgtotext

-- I am returning the recipients of an eMail message as plain text list
on gettxtrecipients(rectype, msg)
   -- I am returning the recipeints as a text list, e.g.:
   -- "Martin Michel <martin@joyofscripting.com>, Steve Jobs <steve@mac.com>"
   -- If there are no recipients availabe, I return «missing value»
   set textrecipients to ""
   tell application "Mail"
       if rectype is "TO" then
           set recpnts to to recipients of msg
       else if rectype is "CC" then
           set recpnts to cc recipients of msg
       else if rectype is "BCC" then
           set recpnts to bcc recipients of msg
       end if
       if recpnts is {} then
           return missing value
       else
           set countrecpnts to length of recpnts
           repeat with i from 1 to countrecpnts
               set recaddress to address of (item i of recpnts)
               set recname to name of (item i of recpnts)
               -- sometimes the «name» property is not available for a recipient,
               -- so we have to use an ugly try...end try-block below:
               if i is equal to countrecpnts then
                   try
                       set textrecipients to textrecipients & recname & " <" & recaddress & ">"
                   on error
                       set textrecipients to textrecipients & "<" & recaddress & ">"
                   end try
               else
                   try
                       set textrecipients to textrecipients & recname & " <" & recaddress & ">, "
                   on error
                       set textrecipients to textrecipients & "<" & recaddress & ">, "
                   end try
               end if
           end repeat
           return textrecipients
       end if
   end tell
end gettxtrecipients

-- I am returning the eMail attachments as a plain text list
on gettxtatms(atms)
   set textatms to ""
   if atms is {} then
       return missing value
   else
       set countatms to length of atms
       if countatms is equal to 1 then
           set textatms to ("1 Attachment:" & return)
       else
           set textatms to (countatms & " Attachments:" & return)
       end if
       tell application "Mail"
           repeat with i from 1 to countatms
               set atm to item i of atms
               set atmname to name of atm
               set atmsize to my getstringsize(file size of atm)
               set atmmime to MIME type of atm
               set atmdl to downloaded of atm
               set atmentry to " «" & atmname & "» (" & atmsize & ")"
               if i is equal to countatms then
                   set textatms to textatms & atmentry
               else
                   set textatms to textatms & atmentry & return
               end if
           end repeat
       end tell
       return textatms
   end if
end gettxtatms

-- I am returning the given byte site in human readable form
on getstringsize(bytesize)
   set pyscriptpath to ((path to me) as Unicode text) & "Contents:Resources:Scripts:utl.py"
   set cmd to "python " & quoted form of (POSIX path of pyscriptpath) & space & bytesize
   set cmd to cmd as «class utf8»
   set shellresult to do shell script cmd
   return shellresult
end getstringsize

-- I am returning the file pathof the eMail message based on its message ID
on getmsgpath(msgid)
   set mailfolder to ((path to library folder from user domain) as Unicode text) & "Mail"
   set cmd to "find " & quoted form of (POSIX path of mailfolder) & space & "-name" & space & msgid & ".emlx"
   set cmd to cmd as «class utf8»
   set shellresult to do shell script cmd
   if shellresult is "" then
       return missing value
   else
       return shellresult
   end if
end getmsgpath

-- I am writing given content to a given file using UTF-8 text encoding
on writetofile(cont, filepath)
   try
       set openfile to open for access filepath with write permission
       set eof of openfile to 0
       set BOM_UTF8 to ((ASCII character 239) & (ASCII character 187) & (ASCII character 191))
       write (cont as «class utf8») to openfile
       close access openfile
       return true
   on error
       try
           close access openfile
       end try
       return false
   end try
end writetofile

-- I am indicating if a given application is currently running
on appisrunning(appname)
   tell application "System Events"
       set processnames to name of processes
   end tell
   if appname is in processnames then
       return true
   else
       return false
   end if
end appisrunning

-- script object to manage a temporary file
script TmpFile
   property filepath : missing value
   
   -- I am creating a new, not yet existing file path in the temp folder
   on newpath()
       set tmpfolderpath to (path to temporary items folder from user domain) as Unicode text
       repeat
           set rndnum to random number from 1000 to 99999
           set tmpfilepath to (tmpfolderpath & (rndnum as Unicode text) & ".tmp")
           try
               set tmpfilepath to tmpfilepath as alias
           on error
               set filepath to tmpfilepath
               exit repeat
           end try
       end repeat
       return filepath
   end newpath
   
   -- I am returning the file path of the temporary file
   on getpath()
       return filepath
   end getpath
   
   -- I am trying to delete the temporary file
   on remove()
       try
           set command to "rm " & quoted form of (POSIX path of (filepath as Unicode text))
           do shell script command
       end try
   end remove
end script


Sal Soghoian is my role model.

Offline

 
  • Index
  •  » Code Exchange
  •  » Automatically print out incoming eMails and attachments in Apple Mail

Board footer

Powered by FluxBB

[ Generated in 0.525 seconds, 8 queries executed ]

RSS (new topics) RSS (active topics)