rccharles

Batch Mailer

Dec 3rd, 2020
3,285
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (*
  2.  
  3. batchMailer.app
  4.  
  5. Send an individual email with an optional attachment to each of the addresses listed in email.txt. Inserts emailers name when present in email.txt file.
  6.  
  7. Input files are in the bulkMailerContents folder in your home folder.  I use the free version of bbedit to create and edit all these files.
  8. Download here:
  9.     https://www.barebones.com/products/bbedit/index.html
  10.  
  11.  
  12. (1) You need to specify the email addresses to send email to in file emails.txt.
  13. example:
  14. #
  15. # Where a leading # is a comment line.
  16. #
  17. # Enter one or more valid email addresses
  18. # Examples are from Snow White and the Seven Dwarfs:
  19. #      Doc, Happy, Grumpy, Bashful, Sneezy, Sleepy, and Dopey.
  20. #      ( dwarves )
  21. #
  22. Sneezy Dwarf <sneezy.dwarf@noname.info>
  23. Sleepy Dwarf <sleepydwarf@noname.net>
  24. grumpy.dwarf@noname.net
  25.  
  26.  
  27. (2) The file content.txt contains the text of your message.
  28. To get a name insertion, you need to include the real name before the email address and include a greeting in the content.txt file. You need
  29. to start the file with a word like Dear followed by a colon (:). For email with a name followed by the email address in <>, the name will be
  30. inserted before the first colen (:). For email address from file emails.txt with a name followed by the email address in <>, the name will be
  31. inserted before the fist colen (:) in the content.txt file.
  32. For example, with an email sent to Sneezy Dwarf <sneezy.dwarf@noname.info> the name Sneezy Dwarfis inserted.
  33. Dear:
  34. will become
  35. Dear Sneezy Dwarf:
  36.  
  37.  
  38. (3) subject.txt contains the subject line.
  39.  
  40.  
  41. (4) To send an attachment, you will have to modify the Applescript code below.
  42. Look for "set attachmentFile".  See the "underlined" code.
  43.    
  44.    
  45. I left in AppleScript log statements for debugging. Select view message tab when running from debugger.
  46.  
  47. Copyright 2020 Robert Janku  
  48.      
  49.        Permission is hereby granted, free of charge, to any person obtaining a copy  
  50.        of this software and associated documentation files (the "Software"), to deal  
  51.        in the Software without restriction, including without limitation the rights  
  52.        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
  53.        copies of the Software, and to permit persons to whom the Software is  
  54.        furnished to do so, subject to the following conditions:  
  55.        
  56.        The above copyright notice and this permission notice shall be included in all  
  57.        copies or substantial portions of the Software.  
  58.        
  59.        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  60.     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  61.     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  62.     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  63.     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  LIABILITY,
  64.     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  65.     FROM,  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
  66.     OR OTHER DEALINGS IN THE SOFTWARE.     
  67.  
  68. *)
  69.  
  70. on run
  71.     global debug
  72.     set debug to 7
  73.     set ht to character id 9
  74.     set lf to character id 10
  75.    
  76.     -- Write a message into the event log.
  77.     log "  --- Starting on " & ((current date) as string) & " --- "
  78.    
  79.     -- name of attachment file. --
  80.     -- note folders are separated with a colon (:)
  81.     -- file excerpt.pdf is in folder bulkMailerContents which is in your home folder.
  82.     try
  83.         set attachmentFile to (path to home folder as text) & "bulkMailerContents:" & "contents.zip" as alias
  84.         --                                                                                                                 --------------
  85.     on error errMsg number n
  86.         -- could be what user wants. Doesn't want to send an attachment.
  87.         set attachmentFile to ""
  88.         log "==> No go with Attachment File. " & errMsg & " with number " & n
  89.     end try
  90.    
  91.    
  92.     -- email sender address  --
  93.    
  94.     if debug ≥ 4 then
  95.         tell application "Mail"
  96.             log "count of account is " & (count of account)
  97.             log item 1 of every account
  98.             log "Email addresses is: " & email addresses of item 1 of every account
  99.         end tell
  100.     end if
  101.    
  102.     tell application "Mail"
  103.         if (count of account) = 0 then
  104.             display dialog "You have not set up your Apple Mail account. Please define a email account for yourself." & return & "Good bye." giving up after 25
  105.             -- ------------------------ good bye. ------------>"
  106.             return 1
  107.         end if
  108.         set theSender to email addresses of item 1 of every account
  109.         if (count of account) > 1 then
  110.             display dialog "You have multiple Mail accounts. Account " & theSender & " will be used." giving up after 25
  111.         end if
  112.     end tell
  113.     if debug ≥ 4 then log "Resulting email addresses to be used is " & theSender
  114.    
  115.    
  116.     -- subject line --
  117.    
  118.     try
  119.         set subjectFile to (path to home folder as text) & "bulkMailerContents:subject.txt" as alias
  120.         -- read in the subject text
  121.         set subjectText to (read subjectFile as «class utf8») as text
  122.     on error errMsg number n
  123.         log "==> No go in with reading subject from file. " & errMsg & " with number " & n
  124.         -- ask user to cough up subject text
  125.         set returnedInfo to display dialog "subject not found in ~/bulkMailerContents/subject.txt." & return & "Type your Subject" default answer ""
  126.         set subjectText to (text returned of returnedInfo)
  127.         if debug ≥ 4 then log "subjectText is " & return & subjectText
  128.     end try
  129.    
  130.    
  131.     set subjectText to adjustCharacters(subjectText)
  132.     if debug ≥ 4 then log "after adusting linends. subjectText is " & return & subjectText
  133.    
  134.    
  135.     -- list of email address(s) -- 
  136.    
  137.     try
  138.         set emailFile to (path to home folder as text) & "bulkMailerContents:emails.txt" as alias
  139.         -- read in all the emails
  140.         set emailFullText to (read emailFile as «class utf8») as text
  141.        
  142.     on error errMsg number n
  143.         display dialog "Could not find file containing email content from file bulkMailerContents:emails.txt. " & errMsg & return & "Good bye." giving up after 25
  144.         log "==> No go in with locating email list file. " & errMsg & " with number " & n & return & " Good bye."
  145.         -- ------------------------ good bye. ------------>"
  146.         return 1
  147.     end try
  148.    
  149.     if debug ≥ 4 then log "emailFullText is " & return & emailFullText
  150.    
  151.     set emailFullText to adjustCharacters(emailFullText)
  152.     -- split on lf.  resulting in a list
  153.     set emailList to textToList(emailFullText, lf)
  154.     set emailList to items 1 thru -2 of emailList -- trim last item to get rid of null last item
  155.    
  156.     if debug ≥ 4 then log " count is " & (count of emailList) & "  emailList  is " & return & emailList
  157.    
  158.     -- gather all email addresses found so we can ask user if we found the correct list of emails.
  159.     -- Found out the hardwary.
  160.     set emailCleanedList to {}
  161.     if debug ≥ 7 then
  162.         log "count of emailCleanedList is " & (count of emailCleanedList)
  163.         log emailCleanedList
  164.     end if
  165.     set myCount to 0
  166.     set endMarker to "##end##"
  167.     if debug ≥ 7 then
  168.         log " endMarker is " & endMarker
  169.         log "(length of endMarker) is " & (length of endMarker)
  170.     end if
  171.    
  172.     repeat with aNamedEmail in emailList
  173.         -- keep track of current record number
  174.         set myCount to myCount + 1
  175.         if debug ≥ 4 then log "----> aNamedEmail is " & aNamedEmail
  176.        
  177.         -- Check for end marker,"##end##", (skip all following records).
  178.         if debug ≥ 4 then
  179.             try
  180.                 if debug ≥ 4 then log "(length of aNamedEmail) is " & (length of aNamedEmail)
  181.                 log "characters 1 thru (length of endMarker) of aNamedEmail is " & characters 1 thru (length of endMarker) of aNamedEmail
  182.             end try
  183.         end if
  184.        
  185.         if (length of aNamedEmail)(length of endMarker) then
  186.             if debug ≥ 7 then log "aNamedEmail is long enough to look for ##end## input marker"
  187.            
  188.             -- done this convoluted way to see what each segment yields.
  189.             if ((characters 1 thru (length of endMarker) of aNamedEmail) as text is endMarker) then
  190.                 if debug ≥ 4 then log "End of processing marker found at record number " & myCount & ". Skip rest of records."
  191.                 -- Done scanning since found end marker.           
  192.                 exit repeat
  193.             end if
  194.         end if
  195.         -- Check for null line
  196.         -- Check for comment line
  197.         -- Check for a blank line          
  198.         -- the # needs to be the first character in the record, so look at line before trimmed.
  199.         set trimmedName to trim_line(aNamedEmail, " ", 0)
  200.         if debug ≥ 4 then log "  after trim;  length of trimmedName is " & length of trimmedName & " trimmedName is " & trimmedName
  201.        
  202.         if trimmedName is not " " and length of aNamedEmail ≥ 1 and character 1 of aNamedEmail is not "#" then
  203.            
  204.             copy aNamedEmail to the end of emailCleanedList
  205.             if debug ≥ 4 then log "    ====> displayEmailText of " & myCount & " is " & aNamedEmail
  206.             if debug ≥ 7 then
  207.                 log "    count of emailCleanedList is " & (count of emailCleanedList)
  208.                 log emailCleanedList
  209.                
  210.             end if
  211.         end if
  212.        
  213.     end repeat
  214.    
  215.     if debug ≥ 4 then log emailCleanedList
  216.     -- gather email addresses for printing
  217.     set displayEmailText to ""
  218.     repeat with emailName in emailCleanedList
  219.         set displayEmailText to displayEmailText & emailName & return
  220.     end repeat
  221.     display dialog ("oK to email these folks?" & return & displayEmailText)
  222.     -- fyi. Saying no quits this applescript.
  223.    
  224.    
  225.     -- get message text --
  226.    
  227.     try
  228.         set contentFile to (path to home folder as text) & "bulkMailerContents:content.txt" as alias
  229.         set emailContent to (read contentFile as «class utf8») as text
  230.     on error errMsg number n
  231.         display dialog "Could not find file containing the message text. " & return & "Create file  ~/bulkMailerContents/content.txt." & return & errMsg & return & " Good bye." giving up after 25
  232.         log "==> No go no content File. " & errMsg & " with number " & n
  233.         -- ------------------------ good bye. ------------>"
  234.         return 1
  235.     end try
  236.     -- convert lineends to lf.
  237.     set emailContent to adjustCharacters(emailContent)
  238.    
  239.     -- Send an email to each address.
  240.     set warningEmailCount to 100
  241.     set numberOfSends to 0
  242.     set userAnswered to 0
  243.     repeat with anEmailAddress in emailCleanedList
  244.        
  245.         if debug ≥ 4 then log "--------------> length of anEmailAddress is " & length of anEmailAddress & " anEmailAddress is " & anEmailAddress
  246.        
  247.         -- do one send
  248.         sendMail(anEmailAddress, theSender, subjectText, emailContent, attachmentFile)
  249.        
  250.         if debug ≥ 5 then log "back in run after sending the email."
  251.         -- Check to display warning message as needed.
  252.         set numberOfSends to numberOfSends + 1
  253.         if numberOfSends ≥ warningEmailCount and userAnswered = 0 then
  254.             display dialog "You have sent " & warningEmailCount & " emails. Last email to " & trimmedName & return & "Many ISPs limit the number of emails you may send." & return & "Do you want to risk sending more emails? (You will not be asked again.)"
  255.             set userAnswered to 1
  256.         end if
  257.        
  258.     end repeat
  259.     if debug ≥ 1 then log "All done! Have a good day from batchMailer."
  260.    
  261. end run
  262.  
  263. -- ============================== Common Subroutines ==========================
  264.  
  265. -- ------------------------------------------------------
  266. (*
  267.  
  268. Recipiet
  269. Sender
  270. Subject
  271. theContent = the content of the email message.  It is assumed that the first line startes with "Dear:". This is changed to include the sender name when suppied.
  272.              example:
  273.              sender is Green Fox <green@domain.info>
  274.              theContents is
  275.                 Dear:
  276.                 ...
  277.              Modify theContents to
  278.                 Dear Green Fox:
  279.                 ...
  280.  
  281. File = points to the file to attach
  282. *)
  283.  
  284. on sendMail(toRecipiet, theSender, theSubject, theContent, aFile)
  285.     global debug
  286.     if debug ≥ 5 then log "in ~~~ sendMail ~~~"
  287.     if debug ≥ 5 then log "toRecipiet is " & toRecipiet
  288.     set buildContent to theContent
  289.     -- Did the email address contian the person's name?
  290.     -- split out name  
  291.     set nameAndAddress to textToList(toRecipiet, "<")
  292.     if (count of nameAndAddress) is 1 then
  293.     else
  294.         -- set adjustedContent to alterString(theContent, ":", first item of nameAndAddress & ":")
  295.         set theOffset to offset of ":" in theContent
  296.         if theOffset > 1 then
  297.             set buildContent to text 1 thru (theOffset - 1) of theContent
  298.             log "    buildContent is " & buildContent
  299.             set buildContent to buildContent & " " & trim_line(first item of nameAndAddress, " ", 2)
  300.             log "    buildContent is " & buildContent
  301.             set buildContent to buildContent & text theOffset thru -1 of theContent
  302.             log "    buildContent is " & buildContent
  303.            
  304.         end if
  305.        
  306.     end if
  307.    
  308.    
  309.     tell application "Mail"
  310.        
  311.         set msg to make new outgoing message with properties {subject:theSubject, content:buildContent as rich text, visible:true, sender:theSender}
  312.        
  313.         tell msg to make new to recipient at end of every to recipient with properties {address:toRecipiet}
  314.        
  315.         -- ignore file not found.
  316.         try
  317.             tell msg to make new attachment with properties {file name:aFile as alias}
  318.         on error errMsg number n
  319.             -- use may not have wanted to send an attachment       
  320.             log "==> No go with Attachment File. " & return & "    " & errMsg & " with number " & n
  321.         end try
  322.        
  323.         send msg
  324.        
  325.     end tell
  326.    
  327. end sendMail
  328. -- ------------------------------------------------------
  329. (*
  330.     Symbol  Meaning                 Hex     Used
  331.         CR      Carriage Return         0d      classic Macintosh
  332.         LF      Line Feed                       0a      UNIX
  333.         CR/LF   Carriage Return/Line Feed   0d0a    MS-DOS, Windows, OS/2
  334.        
  335.     8230    U+2026  E2 80 A6    … Horizontal Ellipsis
  336.         https://www.charset.org/utf-8/9
  337.        &hellip;
  338.         https://www.toptal.com/designers/htmlarrows/punctuation/horizontal-ellipsis/
  339.  
  340.     *)
  341. on adjustCharacters(normalHtml)
  342.     global debug
  343.     set ht to character id 9 -- horizontal tab
  344.     set lf to character id 10
  345.     set ellipsis1 to character id 226
  346.     set ellipsis2 to character id 128
  347.     set ellipsis3 to character id 166
  348.    
  349.     if debug ≥ 3 then log "in --- adjustCharacters() ---"
  350.    
  351.     -- for some reason web broswers are having difficulty with utf-8 E2 80 A6
  352.     -- so convert to a HTML entity.  does work in <pre>
  353.     set normalHtml to alterString(normalHtml, ellipsis1 & ellipsis2 & ellipsis3, "&hellip;")
  354.    
  355.     -- don't let Windoze confuse us. convert Return LineFeed to lf
  356.     set normalHtml to alterString(normalHtml, return & lf, lf)
  357.     -- might as will convert classic macOS return to lf. We will have to look for less things.
  358.     set normalHtml to alterString(normalHtml, return, lf)
  359.     if debug ≥ 3 then hexDumpFormatOne("adjustCharacters: after altering characters normalHtml", normalHtml)
  360.     return normalHtml
  361. end adjustCharacters
  362.  
  363. -- ------------------------------------------------------
  364. (*
  365. alterString
  366.   thisText is the input string to change
  367.   delim is what string to change.  It doesn't have to be a single character.
  368.   replacement is the new string
  369.  
  370.   returns the changed string.
  371. *)
  372.  
  373. on alterString(thisText, delim, replacement)
  374.     global debug
  375.     if debug ≥ 5 then log "in ~~~ alterString ~~~"
  376.     set resultList to {}
  377.     set {tid, my text item delimiters} to {my text item delimiters, delim}
  378.     try
  379.         set resultList to every text item of thisText
  380.         set text item delimiters to replacement
  381.         set resultString to resultList as string
  382.         set my text item delimiters to tid
  383.     on error
  384.         set my text item delimiters to tid
  385.     end try
  386.     return resultString
  387. end alterString
  388.  
  389. -- ------------------------------------------------------
  390. (*
  391. length of inputLfBuffer & " in hex " & integerToHex(length of inputLfBuffer)
  392. *)
  393. on getIntegerAndHex(aNumber)
  394.     global debug
  395.     if debug ≥ 5 then log "in ~~~ getIntegerAndHex ~~~"
  396.    
  397.     return aNumber & " in Hex " & integerToHex(aNumber)
  398. end getIntegerAndHex
  399.  
  400. (*
  401.   http://krypted.com/mac-os-x/to-hex-and-back/
  402.                0    2    4    6    8    a    c    e     0 2 4 6 8 a c e
  403. 0000000:   3c 703e 5369 6d70 6c65 2070 7574 2c20   <p>Simple put,
  404.             *)
  405. on hexDumpFormatOne(textMessage, hex)
  406.     global debug
  407.    
  408.     set aNul to character id 1
  409.    
  410.     if debug ≥ 7 then log "in ~~~ hexDumpFormatOne ~~~"
  411.     if debug ≥ 8 then log "    hexDumpFormatOne: input string is " & return & hex
  412.    
  413.     -- -r -p
  414.     set displayValue to aNul & hex
  415.     set toUnix to "/bin/echo -n " & (quoted form of displayValue) & " | xxd  "
  416.     if debug ≥ 8 then log "    hexDumpFormatOne: toUnix is " & toUnix
  417.    
  418.     try
  419.         set fromUnix to do shell script toUnix
  420.        
  421.         -- two hex digits
  422.         set displayText to replaceCharacter(fromUnix, 10, "  ")
  423.         if debug ≥ 8 then
  424.             log "    hexDumpFormatOne: " & return & displayText
  425.             log "    hexDumpFormatOne: length of displayText is " & length of displayText
  426.         end if
  427.         -- one character
  428.         set displayText to replaceCharacter(displayText, 51, " ")
  429.         if debug ≥ 8 then
  430.             log "    hexDumpFormatOne: " & return & displayText
  431.             log "    hexDumpFormatOne: almost there ..... length of displayText is " & length of displayText
  432.         end if
  433.         log "variable " & textMessage & " in hex is " & return & "         0    2    4    6    8    a    c    e     0 2 4 6 8 a c e" & return & displayText
  434.     on error errMsg number n
  435.         log "    hexDumpFormatOne: ==> convert hex string to string failed. " & errMsg & " with number " & n
  436.     end try
  437.     if debug ≥ 8 then
  438.         log "leaving ~.~ hexDumpFormatOne ~.~"
  439.     end if
  440. end hexDumpFormatOne
  441.  
  442. -- ------------------------------------------------------
  443. (*
  444. https://macscripter.net/viewtopic.php?id=43713
  445.   *)
  446. on integerToHex(nDec)
  447.     global debug
  448.     if debug ≥ 5 then log "in ~~~ integerToHex ~~~"
  449.     try
  450.         set nHex to do shell script "perl -e 'printf(\"%X\", " & nDec & ")'" --> "F0"
  451.     on error errMsg number n
  452.         log "==> convert integer to hex. " & errMsg & " with number " & n
  453.         set nHex to ""
  454.     end try
  455.     return nHex
  456. end integerToHex
  457.  
  458. -- ------------------------------------------------------
  459. (*
  460. StefanK in https://macscripter.net/viewtopic.php?id=43852
  461. Replaces one or more characters based on the length of theCharacter.
  462.  
  463.   Big Warning!!!
  464.   ==============
  465.     This on block is called by hexDumpFormatOne().  
  466.     Therefor, you may not call hexDumpFormatOne() from this on block.
  467.     If you so so, you get yourself into an endless loop.
  468.     Use hexDumpFormatZero() instead.
  469.    
  470.     script -k <output file name>
  471.     osascript /Applications/applescriptFiles/workwithclipboardV13-HTML.app
  472.     use Activity Monito to stop osascript
  473.    
  474. *)
  475.  
  476. on replaceCharacter(theText, theOffset, theCharacter)
  477.     global debug
  478.     if debug ≥ 7 then log "in ~~~ replaceCharacter ~~~"
  479.     if debug ≥ 7 then
  480.         log "  theOffset is " & getIntegerAndHex(theOffset) & " with theCharacter >" & theCharacter & "<  length of theText is " & getIntegerAndHex(length of theText)
  481.         log "theText is " & theText
  482.     end if
  483.    
  484.     set theOutput to theText -- ready to return if need be.
  485.     repeat 1 times
  486.         -- sanity checks
  487.         if theOffset ≤ 0 then
  488.             display dialog "No character to replace at " & theOffset & " with character " & theCharacter & " in " & theText giving up after 10
  489.             log "==> Adjust theOffset to be wihin the string."
  490.             exit repeat -------------- return ---------->                  
  491.         end if
  492.         if (theOffset - (length of theCharacter))0 then
  493.             display dialog "Too near the front of the buffer.  " & theOffset & " with character " & theCharacter & " in " & theText giving up after 10
  494.             log "==> Too near the front of the buffer. "
  495.             exit repeat -------------- return ---------->
  496.         end if
  497.         if (theOffset + (length of theCharacter) - 1) > (length of theText) then
  498.             display dialog "To near the end of the buffer. " & theOffset & " with character " & theCharacter & " in " & theText giving up after 10
  499.             log "==> Too near the end of the buffer. "
  500.             log "  " & "theOffset is " & theOffset & " with theCharacter >" & theCharacter & "<  in " & theText
  501.             log "length of buffer is " & getIntegerAndHex(length of theText)
  502.             exit repeat -------------- return ---------->                  
  503.         end if
  504.        
  505.         if debug ≥ 7 then
  506.             log "theOffset is " & getIntegerAndHex(theOffset)
  507.             log "theCharacter is " & theCharacter
  508.         end if
  509.        
  510.         try
  511.             -- what if we are at the end of the buffer.  We cannot get any remainder text.
  512.             if theOffset ≥ (length of theText) then
  513.                 set theOutput to (text 1 thru (theOffset - 1) of theText) & theCharacter
  514.             else
  515.                 set theOutput to (text 1 thru (theOffset - 1) of theText) & theCharacter & (text (theOffset + (length of theCharacter)) thru -1 of theText)
  516.             end if
  517.         on error errMsg number n
  518.             log "==> No go. " & errMsg & " with number " & n
  519.             exit repeat -------------- return ---------->
  520.         end try
  521.     end repeat
  522.     return theOutput
  523. end replaceCharacter
  524.  
  525. -- ------------------------------------------------------
  526. (*
  527. splitTextToList seems to be what you are trying to do
  528.   thisText is the input string
  529.   delim is what to split on
  530.  
  531.   results returned in a list
  532.  
  533.   Total hack. We know splitTextToList strips of delim so add it back.
  534. *)
  535.  
  536. on splitTextToList(thisText, delim)
  537.     global debug
  538.     if debug ≥ 5 then log "in ~~~ splitTextToList ~~~"
  539.    
  540.     set returnedList to textToList(thisText, delim)
  541.     set resultArray to {}
  542.     copy item 1 of returnedList to the end of the resultArray
  543.    
  544.     repeat with i from 2 to (count of returnedList) in returnedList
  545.         set newElement to delim & item i of returnedList
  546.         copy newElement to the end of the resultArray
  547.     end repeat
  548.    
  549.     return resultArray
  550. end splitTextToList
  551.  
  552. -- ------------------------------------------------------
  553. (*
  554. textToList seems to be what you are trying to do
  555.   thisText is the input string
  556.   delim is what to split on
  557.  
  558.   returns a list of strings.  
  559.  
  560. - textToList was found here:
  561. - http://macscripter.net/viewtopic.php?id=15423
  562.  
  563. *)
  564.  
  565. on textToList(thisText, delim)
  566.     global debug
  567.     if debug ≥ 5 then log "in ~~~ textToList ~~~"
  568.     set resultList to {}
  569.     set {tid, my text item delimiters} to {my text item delimiters, delim}
  570.    
  571.     try
  572.         set resultList to every text item of thisText
  573.         set my text item delimiters to tid
  574.     on error
  575.         set my text item delimiters to tid
  576.     end try
  577.     return resultList
  578. end textToList
  579.  
  580. -- ------------------------------------------------------
  581. (*
  582. Foound here:
  583.     https://www.macosxautomation.com/applescript/sbrt/sbrt-06.html
  584.    
  585.    
  586. Text Manipulation
  587.  
  588. Manipulating text strings is one of the most common tasks performed in scripts. The following sub-routines perform some of the most common text manipulation tasks.
  589. Trim Line
  590.  
  591. The following sub-routine can be used to trim text from the beginning or end of a string. It has three passed parameters:
  592.  
  593.     The text to trim
  594.     The characters to trim from the passed text
  595.     The direction indicator
  596.  
  597. The direction indicator has three possible numeric values:
  598.  
  599. 0, which tells the routine to trim the indicated characters from the beginning of the passed string:
  600.  
  601. set this_text to "----1----"
  602. trim_line(this_text, "-", 0)
  603. --> returns: "1----"
  604.  
  605. 1, which tells the routine to trim the indicated characters from the end of the passed string:
  606.  
  607. set this_text to "12345.txt"
  608. trim_line(this_text, ".txt", 1)
  609. --> returns: "12345"
  610.  
  611. 2, which tells the routine to trim the indicated characters from both ends of the passed string:
  612.  
  613. set this_text to "*-*-fred*-*-"
  614. trim_line(this_text, "*-", 2)
  615. --> returns: "fred"
  616. *)
  617.  
  618. on trim_line(this_text, trim_chars, trim_indicator)
  619.     -- 0 = beginning, 1 = end, 2 = both
  620.     set x to the length of the trim_chars
  621.     -- TRIM BEGINNING
  622.     if the trim_indicator is in {0, 2} then
  623.         repeat while this_text begins with the trim_chars
  624.             try
  625.                 set this_text to characters (x + 1) thru -1 of this_text as string
  626.             on error
  627.                 -- the text contains nothing but the trim characters
  628.                 return ""
  629.             end try
  630.         end repeat
  631.     end if
  632.     -- TRIM ENDING
  633.     if the trim_indicator is in {1, 2} then
  634.         repeat while this_text ends with the trim_chars
  635.             try
  636.                 set this_text to characters 1 thru -(x + 1) of this_text as string
  637.             on error
  638.                 -- the text contains nothing but the trim characters
  639.                 return ""
  640.             end try
  641.         end repeat
  642.     end if
  643.     return this_text
  644. end trim_line
  645.  
  646. (* non-working code
  647. repeat with aName in emailList
  648.         log "--------------> aName is " & aName
  649.         if displayEmailCount = 0 then
  650.             set displayEmailText to displayEmailText & " " & aName
  651.         else
  652.             set displayEmailText to displayEmailText & ", " & aName
  653.         end if
  654.         set displayEmailCount to displayEmailCount + 1
  655.         -- five email addresses per line
  656.         if displayEmailCount ≥ 1 then
  657.             set displayEmailText to displayEmailText & return
  658.             set displayEmailCount to 0
  659.         end if
  660.     end repeat
  661. *)
  662. (*
  663. log (characters 1 thru (length of endMarker) of aName is endMarker)
  664.             log (characters 1 thru (length of endMarker) of aName) as text
  665.             log "class of endMarker is " & class of endMarker
  666.             set evaluatedExpression to (characters 1 thru (length of endMarker) of aName) as text
  667.             log "evaluatedExpression is " & evaluatedExpression
  668.             log "class of characters...  " & class of evaluatedExpression
  669. *)
  670.  
RAW Paste Data