Save or export direct from clipboard into PDF file

HI

I have been scouring the posts and am left wondering if it is possible to have Applescript (or a shell command via Applescript) export the contents of the clipboard (maintaining formatting etc) into a new PDF file.

I have seen that you can create a new Textedit document, paste the clipboard then export as PDF. But I want this to work in the background, without disturbing the user.

I am actually looking at this as a way to automatically archive certain Mail messages as they come in. Copy contents of the message to clipboard, export to PDF in a particular folder…

Am I wasting my time?

Thanks

After copying a block of datas from a Web page, I ran a huge script :


clipboard info

The log report was :

{{«class weba», 102161}, {«class rtfd», 57301}, {«class RTF », 19733}, {«class utf8», 2281}, {«class ut16», 4624}, {uniform styles, 22836}, {string, 2311}, {scrap styles, 3722}, {Unicode text, 4462}, {uniform styles, 22836}, {scrap styles, 3722}}

So, it seems that the step RTF/rtfd is required.

I never tried but I guess that writing the RTF component of the clipboard in a file would be trivial.
Alas, I have no idea about a way to do the same with the rtfd component.

Yvan KOENIG (VALLAURIS, France) vendredi 1 février 2013 18:46:51

Hi Yvan

I am trying to go the more roundabout way but it is not easy.

If you select a message in Mail, copy it and paste it into TextEdit, it will appear in rich text/formatted etc in TexEdit.

But I am unable to achieve this result using Applescript. Getting the content of a mail message gives you simple text only - all formatting is lost.

I cannot use GUI scripting as I want the script to act on Mail when received (not when selected).

Any ideas?

I apologize but I don’t know a way to do the trick without GUI scripting.

Here is a piece of code doing the job with the contents of the clipboard without knowing the source of the datas.


tell application "TextEdit"
	activate
	make new document
end tell
tell application "System Events" to tell application process "TextEdit"
	tell menu bar 1 to tell menu bar item 5 to tell menu 1
		# name of menu items
		--> {"Police", "Texte", missing value, "Convertir au format RTF", "Empêcher les modifications", "Adapter à la page", "Permettre la césure", "Présentation verticale", missing value, "Liste.", "Tableau."}
		get enabled of menu item -1
		if result is false then click menu item 4 # force rich text format
		--> menu item "Convertir au format RTF" of menu "Format" of menu bar item "Format" of menu bar 1 of application process "TextEdit"
	end tell
	tell window 1
		keystroke "v" using {command down} -- paste
		keystroke "s" using {command down} -- save
		repeat
			delay 0.1
			if exists sheet 1 then exit repeat
		end repeat
		keystroke "d" using {command down} -- define Desktop as target folder
		
		tell sheet 1 to tell text field 1
			set nameExt to item -1 of my decoupe(value, ".")
			tell me to (do shell script "date +_%Y%m%d_%H%M%S.") & nameExt
			set value to result
		end tell
		
	end tell
	
	keystroke return
	
end tell
# Now the rtf/rtfd file is stored on the Desktop.
# Alternate scheme, print it in a PDF without saving it as rtf/rtfd

#=====

on decoupe(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

#=====

I am able to write the variant printing the TextEdit document in a PDF
but it seems that it would be wasting time as it doesn’t match your needs.

Yvan KOENIG (VALLAURIS, France) vendredi 1 février 2013 22:41:48

Thank Yvan

I have put together the script below, which lacks any real sophistication for the moment. It works on the selected Mail message, exports it as RTF using Mail’s ability to do this, while at the same time date/time stamping the RTF using the date sent variable from Mail. The resulting RTF file is then opened in TextEdit which has an Export as PDF option… Gets the job done as a GUI workaround. However, I want this script to work as a Mail Rule (ie work on the particular Mail message which triggers the Mail Rule), which is defeating me for the moment…

Others may have to play around with the delays in the GUI scripting. I have SSDs everywhere now!

Until someone much better at applescript can suggest a non GUI solution. Even if I could eliminate the TextEdit part… must be some clever way of taking an RTF file with a shell command and produce a PDF…

Cheers

tell application "Mail"
	activate
	set messges to selection
	set messge to item 1 of messges
	set datesent to date sent of messge
	set datetimetext to my makeStamp(datesent, "-", "|", "_")
	set datetext to rich text 1 thru 10 of datetimetext
	set timetext to rich text 12 thru 19 of datetimetext
	set flname to datetext & " Mail Message " & timetext
	set tempclip to the clipboard
	set the clipboard to flname
	my mailGUI(1)
	delay 1
	set test to my mailGUI(3)
	if test is true then
		my mailGUI(2)
	end if
	set the clipboard to tempclip
end tell

delay 1

set filepath to ((path to documents folder) as text) & "MailMessages:" & flname & ".rtf"
set targetfile to filepath as alias


tell application "TextEdit"
	activate
	open targetfile
	set test to my TextEditGUI(3, flname)
	my TextEditGUI(1, 0)
	delay 1
	set test to my TextEditGUI(2, 0)
	delay 1
	close document flname
end tell




on makeStamp(Now, DelimD, DelimT, SepT) -- the first delim for date, the second for time, the third to separate date and time.
	tell Now to tell 100000000 + day * 1000000 + (its month) * 10000 + year as string ¬
		to set dateStamp to text -4 thru -1 & DelimD & text 4 thru 5 & DelimD & text 2 thru 3
	tell Now to tell ((1000000 + (its hours) * 10000 + (its minutes) * 100 + (its seconds)) as string) ¬
		to set timeStamp to text 2 thru 3 & DelimT & text 4 thru 5 & DelimT & text 6 thru 7
	return dateStamp & SepT & timeStamp
end makeStamp

on mailGUI(choice)
	tell application "System Events"
		tell process "Mail"
			if choice is equal to 1 then
				click menu item "Save As." of menu 1 of menu bar item "File" of menu bar 1
			else if choice is equal to 2 then
				click menu item "Paste" of menu 1 of menu bar item "Edit" of menu bar 1
				delay 0.5
				keystroke return
			else if choice is equal to 3 then
				repeat with n from 1 to 5
					if exists sheet 1 of window 1 then
						return true
					end if
					delay 1
				end repeat
				return false
			end if
		end tell
	end tell
end mailGUI


on TextEditGUI(choice, nme)
	tell application "System Events"
		tell process "TextEdit"
			if choice is equal to 1 then
				click menu item "Export as PDF." of menu 1 of menu bar item "File" of menu bar 1
			else if choice is equal to 2 then
				repeat with n from 1 to 5
					if exists sheet 1 of window 1 then
						delay 0.5
						keystroke return
						return true
					end if
					delay 1
				end repeat
				return false
			else if choice is equal to 3 then
				repeat with n from 1 to 5
					if exists window nme then
						delay 0.5
						return true
					end if
					delay 1
				end repeat
				return false
			end if
		end tell
	end tell
end TextEditGUI

If the contents is Rtf without any picture, the contents may be save in a flat rtf file (opposite of rtfd package) you may drop TextEdit

try :


set rtfDatas to the clipboard as «class RTF»
tell application "System Events to make new file at folder theDestinationFolder with properties {name:"wantedName.rtf"
end
set targetFile to thedestinationFolder:wantedName.rtf as alias
set eof of targetfile to 0 # useful if the file already existed
write rtfdatas to targetFile

But I repeat, it’s only OK for rtf, not rtfd.

I wish to add that creating a date stamp yyyy-mm-dd is better than the dd-mm-yyyy one which you use.
It’s more efficient when a sort is required

With yous the sort will return
01-01-yyyy.
01-02-yyyy. # 02 is the month
.
01-12-yyyy. # 12 is the month
02-01-yyyy. # 01 is the month
.

The alternate one will return
yyyy-01-01.
yyyy-01-02. # 02 is the day
yyyy-01-02. # 03 is the day
.
yyyy-02-01. # 02 is the month, 01 is the day

Yvan KOENIG (VALLAURIS, France) samedi 2 février 2013 10:47:47

Thanks Yvan

I am looking to end up with PDF file, not RTF. I guess if I am having to resort to GUI, easiest way is to GUI the Print Dialog from Mail

Cheers

I am almost done, but am having a little problem selecting the right message to print.

I have the script below which reacts to a Mail rule. However, the problem is that it prints the selected message in the Message Viewer, which is not the message which has just triggered the rule. How do I get Mail to select the message that has just triggered the rule?

Thanks

[BTW, for those wishing to use this script, I use Default Folder to ensure that the printed PDF goes to a particular favourite folder. If you have not got Default Folder installed, I am not sure how you would select a folder using GUI through Mail.]

using terms from application "Mail"
	on perform mail action with messages theMessages for rule theRule
		
		tell application "Mail"
			activate
			repeat with eachMessage in theMessages
				set datesent to date sent of eachMessage
				set datetimetext to my makeStamp(datesent, "-", "|", "_")
				set datetext to rich text 1 thru 10 of datetimetext
				set timetext to rich text 12 thru 19 of datetimetext
				set flname to datetext & " Printed Receipt " & timetext
				set tempclip to the clipboard
				set the clipboard to flname
				my mailGUI(1)
				delay 1
				set test to my mailGUI(3)
				if test is true then set test to my mailGUI(4)
				if test is true then my mailGUI(2)
				set the clipboard to tempclip
			end repeat
		end tell
		
	end perform mail action with messages
end using terms from

on makeStamp(Now, DelimD, DelimT, SepT) -- the first delim for date, the second for time, the third to separate date and time.
	tell Now to tell 100000000 + day * 1000000 + (its month) * 10000 + year as string ¬
		to set dateStamp to text -4 thru -1 & DelimD & text 4 thru 5 & DelimD & text 2 thru 3
	tell Now to tell ((1000000 + (its hours) * 10000 + (its minutes) * 100 + (its seconds)) as string) ¬
		to set timeStamp to text 2 thru 3 & DelimT & text 4 thru 5 & DelimT & text 6 thru 7
	return dateStamp & SepT & timeStamp
end makeStamp

on mailGUI(choice)
	tell application "System Events"
		tell process "Mail"
			if choice is equal to 1 then
				click menu item "Print." of menu 1 of menu bar item "File" of menu bar 1
			else if choice is equal to 2 then
				click menu item "Paste" of menu 1 of menu bar item "Edit" of menu bar 1
				delay 1
				keystroke return
			else if choice is equal to 3 then
				repeat with n from 1 to 5
					if exists sheet 1 of window 1 then
						keystroke "p" using command down
						delay 0.5
						return true
					end if
					delay 1
				end repeat
				return false
			else if choice is equal to 4 then
				repeat with n from 1 to 5
					if exists sheet 1 of sheet 1 of window 1 then
						delay 0.5
						keystroke "p" using command down
						delay 0.5
						return true
					end if
					delay 1
				end repeat
				return false
			end if
		end tell
	end tell
end mailGUI




When I must use GUIscripting to save a file, with the Save dialog open, I issue the instruction

keystroke “d” using {command down}

It defines the Desktop as the target location so, the user just need to move the saved file from the Desktop to the wanted final location.
It’s cleaner than attempts to define the target-folder in Mail’s preferences file which requires to quit then restart Mail.
more, under 10.8.x, the target-folder-i-which-PDF-is-stored is no longer stored in Mail’s own preferences file.

For the behavior of a script triggered by a rule I can’t help because I have no free time to study this feature for which I never wrote before.

Yvan KOENIG (VALLAURIS, France) lundi 4 février 2013 22:16:19

Thanks Yvan

I have put this together, which seems to do the trick, and sends email to confirm:

using terms from application "Mail"
	on perform mail action with messages theMessages for rule theRule
		
		tell application "Mail"
			activate
			delay 1
			tell application "System Events"
				tell process "Mail"
					keystroke "1" using command down -- set view to inbox
				end tell
			end tell
			delay 1
			repeat with eachMessage in theMessages
				set datesent to date sent of eachMessage
				set messageID to id of eachMessage
				set datetimetext to my makeStamp(datesent, "-", "|", "_")
				set datetext to rich text 1 thru 10 of datetimetext
				set timetext to rich text 12 thru 19 of datetimetext
				set flname to datetext & " Scanned Receipt for Business " & timetext & " (SNCF)"
				set tempclip to the clipboard
				set the clipboard to flname
				delay 1
				set selected messages of first message viewer to {first message of mailbox "INBOX" of account "Gmail" whose id is messageID}
				display dialog "Preparing to print email: " giving up after 5
				delay 2
				my mailGUI(1)
				delay 1
				set test to my mailGUI(3)
				if test is true then set test to my mailGUI(4)
				if test is true then my mailGUI(2)
				set the clipboard to tempclip
				delay 3
				set theToRecipient to "youraddress@gmail.com"
				set theSubject to "CONFIRMED: " & the subject of eachMessage
				set theContent to "Logged - CONFIRMED"
				set newMessage to make new outgoing message with properties {subject:theSubject, content:theContent, visible:true}
				delay 2
				tell newMessage
					make new to recipient at end with properties {address:theToRecipient}
					delay 2
					send newMessage
				end tell
			end repeat
		end tell
		
	end perform mail action with messages
end using terms from

on makeStamp(Now, DelimD, DelimT, SepT) -- the first delim for date, the second for time, the third to separate date and time.
	tell Now to tell 100000000 + day * 1000000 + (its month) * 10000 + year as string ¬
		to set dateStamp to text -4 thru -1 & DelimD & text 4 thru 5 & DelimD & text 2 thru 3
	tell Now to tell ((1000000 + (its hours) * 10000 + (its minutes) * 100 + (its seconds)) as string) ¬
		to set timeStamp to text 2 thru 3 & DelimT & text 4 thru 5 & DelimT & text 6 thru 7
	return dateStamp & SepT & timeStamp
end makeStamp

on mailGUI(choice)
	tell application "System Events"
		tell process "Mail"
			if choice is equal to 1 then
				click menu item "Print." of menu 1 of menu bar item "File" of menu bar 1
			else if choice is equal to 2 then
				click menu item "Paste" of menu 1 of menu bar item "Edit" of menu bar 1
				delay 1
				keystroke return
			else if choice is equal to 3 then
				repeat with n from 1 to 5
					if exists sheet 1 of window 1 then
						keystroke "p" using command down
						delay 0.5
						return true
					end if
					delay 1
				end repeat
				return false
			else if choice is equal to 4 then
				repeat with n from 1 to 5
					if exists sheet 1 of sheet 1 of window 1 then
						delay 0.5
						keystroke "p" using command down
						delay 0.5
						return true
					end if
					delay 1
				end repeat
				return false
			end if
		end tell
	end tell
end mailGUI