I am currently trying to customize an AppleScript that is reading the unread Mails in the Inbox.
That basically works fine except the fact, that I can#T manage to get the date of the mails.
After about 2 hours of googling around I found out that the Variable I need should be receivedate or deliverydate, but when trying to use one of these I get an error like this:
"...receivedate of id... cannot be converted to Type reference..."
Someone's got an Idea, how I can convert this?
And this is my current code:
tell application "System Events"
set processList to (name of every process)
end tell
if processList contains "Mail" then
tell application "Mail"
if (unread count of inbox) > 0 then
set messageList to (messages of inbox) whose read status is false
set output to "Mails:" & return & return & ""
repeat with itemNum from 1 to (unread count of inbox)
set itemDate to (receivedate of item itemNum of messageList)
set output to output & itemDate & " - " & (extract name from sender of item itemNum of messageList) & return & subject of item itemNum of messageList & return & return
end repeat
end if
end tell
else
set output to "ÄpplMäil isch aus..."
end if
The term you are looking for is date received
tell application "Mail" to if running then
if (unread count of inbox) > 0 then
set output to "Mails:" & return & return & ""
repeat with thisMsg in (get messages of inbox whose read status is false)
tell thisMsg to set output to output & (date received) & " - " & (extract name from sender) & return & subject & return & return
end repeat
end if
else
set output to "ÄpplMäil isch aus..."
end if
A quicker way to get the help you need is the Applescript dictionarie of Mail.
All commands, classes and properties of Mail are in this dictionary.
One way of opening this dictionary is to use the Open Dictionary item in the File menu of AppleScript Editor. When you use this item, you will get a listing of the available applications that have dictionaries. Choose Mail and click the Open button or use the Browse button to navigate to an unlisted application.
Another way to open a dictionary, is to make use of AppleScript Editor's Library window. It's located in the Window menu below the Result History and Event Log History menu items. The Library window shows a list of default applications whose dictionaries you can open with a double click.
Related
Want to Select Multiple messages in Mail.app, then
1.move them to a folder "AdvertRule"
2.Add Condition (sender's email address) to existing rule "TestRule 23"
Results from Code
works perfectly
Partial, wud add condition to the rule, x times if x number of messages selected, and all emails addresses in same condition as in ( a#aa.com b#bb.com c#cc.com)
Wondering if can be helped to get 1 email address for each condition in the Rule
even better if has error correction (wud not form a new Condition if it already exists)
Tx in advance
(*
Based on
https://apple.stackexchange.com/questions/149008/in-mail-app-get-list-of-recipients-for-just-one-of-the-many-email-accounts
https://discussions.apple.com/thread/7319379
Move selected Messages to another Folder
*)
tell application "Mail"
set theSenderList to {}
set target_account to "Exchange"
set target_mailbox to "AdvertRule"
set theMessages to the selected messages of message viewer 0
repeat with aMessage in theMessages
set end of theSenderList to (extract address from sender of aMessage)
set oldDelimits to AppleScript's text item delimiters
set AppleScript's text item delimiters to " "
set theSender to (theSenderList as string)
set AppleScript's text item delimiters to oldDelimits
end repeat
set r to rule "TestRule 23"
set s to selection
if s is not "" then
repeat with currentMessage in s
move currentMessage to (first mailbox whose name is target_mailbox) of account target_account
tell r
make new rule condition at end of rule conditions with properties {expression:theSender, qualifier:does contain value, rule type:from header}
end tell
end repeat
end if
end tell
Hey after reading thru the applescript for beginners
After getting Sender List, then add rule with every sender in the sender list, then with every message in selection, move the message
That shud work
I accidentally added about 600 contacts to my Mac addressbook from a friend's iPhone I synced to my Mac a couple weeks ago. Unfortunately I dont have a backup of my contacts and now they are all synced with my iPhone and iCloud.
I was able to export all the unwanted contacts as ".vcf" files from my friends phone so I have about 600 files like "John Doe.vcf" and also a plain text list of just the contact names.
Ideally I would like a script that matches the data inside the VCF file to make sure I'm deleteing the right contact.
Idea #2 would be to delete the contacts that matches the name in list, skipping the searches that return two or more results (that way I dont lose my own contacts with same name as my friend's)
I started by attempint to delete a single contact using the following applescript but with no luck. Please help!
set daName to "John Doe"
tell application "Contacts"
repeat with onePerson in people
if (value of name of onePerson) is daName then
delete onePerson
end if
end repeat
end tell
--UPDATE--
Here is the final code I used to perform the task. I added a loop at the top that cycles through the list of names copied in the clipboard. I also added the name of the duplicated contact in the dialog box so I could take note of it.
Tips:
Make a backup of all your contacts before running the script.
If you want to see the number of contacts "magically" decreasing
while running the script, scroll down to the of your contacts in
your address book and you'll see the totla amount of contacts
there.
FINAL CODE
set the clipboard to (the clipboard as text)
set the_strings to the clipboard
repeat with this_string in paragraphs of the_strings
set daName to this_string
DeleteContact(daName)
end repeat
on DeleteContact(theName)
tell application "Contacts"
set myList to every person whose name is theName
set Nb to count of myList
if Nb = 0 then return -- no record found
if Nb > 1 then
display dialog theName & " (too many found: do nothing)"
else
set myperson to item 1 of myList -- only 1 found to be deleted
delete myperson
save
end if
end tell
end DeleteContact
The script bellow contains sub-routine which check name and delete. I added some comments to make it easier to adapt for your need :you can build a loop looking for your card and calling the DeleteContact sub-routine.
set daName to "John Doe"
DeleteContact(daName)
on DeleteContact(theName)
tell application "Contacts"
set myList to every person whose name is theName
set Nb to count of myList
if Nb = 0 then return -- no record found
if Nb > 1 then
display dialog "too many found: do nothing"
else
set myperson to item 1 of myList -- only 1 found to be deleted
delete myperson
save
end if
end tell
end DeleteContact
In case same name exist in multiple contact, I display a dialog, but up to you to decide what to do here.
Gio
This is a script I had and it may address your problem although you never said what the problem was.
tell application "Contacts"
local results,dlist,dloop
set results to {}
set dlist to people whose (first name contains "Oxnard" or (last name is equal to "Abercrombe"))
repeat with dloop in dlist
delete dloop
end repeat
set end of results to "Records deleted :" & count of dlist
save
return results
end tell
Note that the Contacts dictionary does define a name property however it will be based on preference settings.
I've posted here before under a different account name and thanks all for previous help.
I have a spreadsheet which extracts information from a Data Historian, to generate a report on the status of the factory which is then automatically emailed out via Lotus Notes to recipients at fixed time intervals.
Sometimes there may be network issues affecting either the factory DCS, Data Historian (Aspen), or Lotus Notes. This gives a run time error when the script runs. Usually all that is required is to end the script, wait a period of time, recalculate the sheet, and then re-run the script.
Was hoping somebody could advise what code to add to achieve this. All I really need to know is what code to write and where to insert it to end the script in the event of a run-time error, and then to trigger another sub-routine in which I can add an application.wait and application.calculate before re-running the script. I need the script to end and run a separate sub as it causes issues with multiple scheduled events otherwise which then ultimately sends out multiple emails.
I've marked the part of the script that usually fails.
Sub Macro6()
Windows("Silo report 2 hourly.xlsm").Activate
' Range("A1").Select
'Calculate all workbooks
Application.Calculate
'Set up the objects required for Automation into lotus notes
Dim Maildb As Object 'The mail database
Dim UserName As String 'The current users notes name
Dim MailDbName As String 'THe current users notes mail database name
Dim MailDoc As Object 'The mail document itself
Dim AttachME As Object 'The attachment richtextfile object
Dim Session As Object 'The notes session
Dim EmbedObj As Object 'The embedded object (Attachment)
'Start a session to notes
Set Session = CreateObject("Notes.NotesSession")
'Next line only works with 5.x and above. Replace password with your password
'Get the sessions username and then calculate the mail file name
'You may or may not need this as for MailDBname with some systems you
'can pass an empty string or using above password you can use other mailboxes.
UserName = Session.UserName
MailDbName = Left$(UserName, 1) & Right$(UserName, (Len(UserName) - InStr(1, UserName, " "))) & ".nsf"
'Open the mail database in notes
Set Maildb = Session.GETDATABASE("", MailDbName)
If Maildb.IsOpen = True Then
'Already open for mail
Else
Maildb.OPENMAIL
End If
'Set up the new mail document
Set MailDoc = Maildb.CreateDocument
MailDoc.Form = "Memo"
vaRecipient = VBA.Array("xxx.xxx#xxx.com", "yyy.yyy#yyy.com", "zzz.zzz#zzz.com")
MailDoc.SendTo = vaRecipient
MailDoc.Subject = Range("B1").Value
Set workspace = CreateObject("Notes.NotesUIWorkspace")
'**THE RUNTIME ERROR USUALLY OCCURS WITHIN THE NEXT 5 LINES OF SCRIPT**
Dim notesUIDoc As Object
Set notesUIDoc = workspace.EditDocument(True, MailDoc)
Call notesUIDoc.GOTOFIELD("Body")
Call notesUIDoc.FieldClear("Body")
Call notesUIDoc.FieldAppendText("Body", Range("B9").Value & vbCrLf & vbCrLf & Range("b10").Value & Range("I10").Value & Range("D10").Value & vbCrLf & Range("b11").Value & Range("I11").Value & Range("D11").Value & vbCrLf & Range("b12").Value & Range("I12").Value & Range("D12").Value & vbCrLf & vbCrLf & Range("b13").Value & Range("I13").Value & Range("D13").Value & vbCrLf & vbCrLf & Range("b14").Value & Range("C14").Value & Range("D14").Value & vbCrLf & vbCrLf & Range("b15").Value & Range("I15").Value & Range("D15").Value & vbCrLf)
notesUIDoc.Send
notesUIDoc.Close
MailDoc.PostedDate = Now() 'Gets the mail to appear in the sent items folder
'MailDoc.Send 0, vaRecipient
'Clean Up
Set Maildb = Nothing
Set MailDoc = Nothing
Set AttachME = Nothing
Set Session = Nothing
Set EmbedObj = Nothing
End Sub
In LotusScript as well as in Visual Basic / VBA the error handling works exact the same. At the beginning of your Script you define where to go if an error occurs:
On Error Goto ErrorHandler
Place a Jump- Mark above the line, where you want to start over, when the error occurs:
TryAgain:
At the very end of your sub you define the errorhandler itself:
EndSub:
'- prohibit that error handler is called without an error
Exit Sub
ErrorHandler:
'- here you can react on the error, e.g. check for the err (Error number)
If err = NumberOfErrorThatOccursWhenNetworkErrorOccurs then
'- wait some time to give the network time to recover
Sleep x '- put in x as best for your problem
'- jump back
Resume TryAgain
Else
'- another error occured: inform user
Messagebox err & ", " & Error & " in line " & Erl
'- now jump to the end of the sub
Resume EndSub
End If
Of course this is a minimal errorhandling, and probably you would not want to jump around without further checks, but the idea should be clear with this example.
Just one more thing from the comments: you don't need the ui- stuff at all! Just omit it, as it is totally unneccessary and makes your code unstable.
Replace the whole paragraph starting with Set workspace... ending with notesUIDoc.close with two lines of code:
Call Maildoc.ReplaceItemValue( "Body", Range("B9").Value ..... )
Call Maildoc.Send( False )
Then you don't have to take care if something goes wrong - the document will just be discarded when the code runs again or ends, and it will be much more stable than handling ui windows and the screen will not flicker...
I'm attempting to create a script that "walks" through a mailbox, checks the Address Book to see if the e-mail's sender is already there, and adds the contact to an Address Book group if found. If the e-mail's sender isn't found, a new contact would be created before it was added to the group.
So far, I've got this for the group adding part:
on addPersonToGroup(person)
tell application "Address Book"
add person to group "wedding guests"
end tell
save addressbook
end addPersonToGroup
and this for looping through selected messages:
tell application "Mail"
set selectedMessages to selection
if (count of selectedMessages) is equal to 0 then
display alert "No Messages Selected" message "Select the messages you want to add to 'wedding guests' address book group before running this script."
else
set weddingGuests to {}
repeat with eachMessage in selectedMessages
set emailAddress to extract address from sender of eachMessage
--if emailAddress is found in Address Book then
-- get the person from the Address Book
--else
-- create new person with emailAddress
--end if
--addPersonToGroup person
end repeat
end if
end tell
The commented-out part inside the "repeat with eachMessage ..." block is what I haven't figured out yet.
What ways are available for searching the Address Book for an e-mail address using AppleScript? Are there alternative scripting languages on the Mac that would be more suitable for such a task?
Below is the script that ultimately got me the result I wanted. Thanks to #fireshadow52 for the assist:
tell application "Mail"
set selectedMessages to selection
if (count of selectedMessages) is equal to 0 then
display alert "No Messages Selected" message "Select the messages you want to add to 'wedding guests' address book group before running this script."
else
set weddingGuests to {}
repeat with eachMessage in selectedMessages
set emailSender to (extract name from sender of eachMessage) as string
set emailAddress to (extract address from sender of eachMessage) as string
my addSender(emailSender, emailAddress)
end repeat
end if
end tell
on splitText(delimiter, someText)
set prevTIDs to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set output to text items of someText
set AppleScript's text item delimiters to prevTIDs
return output
end splitText
on addSender(theSender, theEmail)
tell application "Address Book"
set tmp to my splitText(" ", theSender)
set numOfItems to count tmp
set senderFirst to item 1 of tmp
if (numOfItems) is greater than 1 then
set senderLast to item 2 of tmp
else
set senderLast to ""
end if
try
set the check to get first person whose first name is senderFirst and last name is senderLast
--No error, sender exists
my addPersonToGroup(check)
on error --sender is not in Address Book yet; add sender and email to contacts and add the new contact to group
set newPerson to (make new person with properties {first name:senderFirst, last name:senderLast})
--Add Email
make new email at the end of emails of newPerson with properties {label:"Email:", value:theEmail}
--add the new person to the group
my addPersonToGroup(newPerson)
end try
end tell
end addSender
on addPersonToGroup(theSender)
tell application "Address Book"
add theSender to group "wedding guests"
save
end tell
end addPersonToGroup
Believe it or not you kind of wrote the answer in the question!
--In your "looping through selected messages" script, add this line...
set emailSender to (get sender of eachMessage) as string
--...before this one...
set emailAddress to (extract address from sender of eachMessage) as string
--This will help you later
--You should add this subroutine at the bottom of your script to check whether the contact exists or not; invoke it by doing 'my addSender(emailSender, emailAddress)'
on addSender(theSender, theEmail)
tell application "Address Book"
set the check to (get first person whose first name is theSender) as list
if check is {} --sender is not in Address Book yet; add sender and email to contacts and add the new contact to group
set newPerson to (make new person with properties {first name:theSender, last name:null}) --Sorry if you want the last name too
--Add Email
make new email at the end of emails of newPerson with properties {label:"Email:", value:theEmail}
--add the new person to the group
my addPersonToGroup(newPerson)
else --sender is in Address Book, add sender to group
my addPersonToGroup(check)
end if
end tell
end addSender
As always, if you need help, just ask. :)
P.S. If you get an error in the subroutine, it is most likely the if block's fault. To fix the error (and to keep the script running), just change the if block to a try block, as shown here:
try
set check to (get first person whose first name is theSender) as list
--No error, sender exists
my addPersonToGroup(check)
on error --Error, sender is not in Address Book yet; add sender and email to contacts and add the new contact to group
set newPerson to (make new person with properties {first name:theSender, last name:null}) --Sorry if you want the last name too
--Add Email
make new email at the end of emails of newPerson with properties {label:"Email:", value:theEmail}
--add the new person to the group
my addPersonToGroup(newPerson)
end try
P.P.S. person is a reserved word for Address Book. Change person to some other variable and it will work (referring to the addPersonToGroup subroutine).
I have a tab control on a form, and a couple different tabs have save buttons on them. Once the user saves data (via SQL statements in VBA), I set the .enabled = false so that they cannot use this button again until moving to a brand new record (which is a button click on the overall form).
so when my form open i was going to reference a sub that enabled all these save buttons because the open event would mean new record. though i get an error that says it either does not exist, or is closed.
any ideas?
thanks
EDIT:
Sub Example()
error handling
Dim db as dao.database
dim rs as dao.recordset
dim sql as string
SQL = "INSERT INTO tblMain (Name, Address, CITY) VALUES ("
if not isnull (me.name) then
sql = sql & """" & me.name & ""","
else
sql = sql & " NULL,"
end if
if not insull(me.adress) then
sql = sql & " """ & me.address & ""","
else
sql = sql & " NULL,"
end if
if not isnull(me.city) then
sql = sql & " """ & me.city & ""","
else
sql = sql & " NULL,"
end if
'debug.print(sql)
set db = currentdb
db.execute (sql)
MsgBox "Changes were successfully saved"
me.MyTabCtl.Pages.Item("SecondPage").setfocus
me.cmdSaveInfo.enabled = false
and then on then the cmdSave needs to get re enabled on a new record (which by the way, this form is unbound), so it all happens when the form is re-opened. I tried this:
Sub Form_Open()
me.cmdSaveInfo.enabled = true
End Sub
and this is where I get the error stated above. So this is also not the tab that has focus when the form opens. Is that why I get this error? I cannot enable or disable a control when the tab is not showing?
You cannot use the form open event to manipulate controls, they have not been initiated at that stage. Use the form load event.
It should never be necessary to set focus to a tab, or even to reference it when working with a control. You will notice that controls must have names unique to the form, and adding a tab does not change this.
I suggest you set some form-level variables: booBtn_1_enabled as Boolean, booBtn_2_enabled as Boolean. Set these to T or F as needed; obviously, all T when the form is opened. Pick a form event (possibly the Current event, but preferably one that is triggered less often) that reviews these variables and sets the controls accordingly:
Me.btnBtn_1.Enabled = booBtn_1_enabled
Me.Repaint
Something like that, but obviously Me.btnBtn_1 may need a more complicated reference.