A colleague approached me with this very important business problem:
Every Friday at SAS HQ, SAS cafe staff provides a breakfast goodie in our breakrooms. Often the supplied goodie is delicious, but sometimes it's more...well...healthy. I want to know whether I should eat my breakfast before I leave home on Friday morning, or if it's better to save my calories for the breakfast goodie at SAS. Can I write a SAS program to send me a text message on Friday morning with the "goodie news" so I can make an informed decision?
Find the data source
SAS HQ publishes the cafeteria menus on our intranet each day, and on Thursday the published menu includes an entry for the planned Friday goodie. Thus, we know that this "data" is available somewhere. My colleague had the idea of using FILENAME URL or PROC HTTP to have SAS read the cafe's menu web page and parse the details about the breakfast goodie. That's one way to do it, but here's something that I know about web pages: they all have source files somewhere that are used to generate the content you see in the browser. If you can gain access to that source file instead of going through the web server, you'll have a much simpler process.
With a little spelunking on the SAS network, I found the source files that feed the cafe menus. ("Feed" -- see what I did there?) The file with the goodie news is an HTML file that is named with a predictable date stamp. Here's the name for today: "../menus/DailyMenus/BreakfastWeb20160812.html". The source file looks like this:
<!-- Published on Thursday, August 11, 2016 01:02 PM--> <h2 class="menuHeader">Friday Breakfast Goodie</h2> <div class="entry fridayGoodie"><div class="menuLeft"><div class="menuLeftContent"> <span class="entryName">Blueberry Almond Crunch Teacake</span> </div></div></div>
We want just the goodie name. With a file reference to the menu file, we can easily parse this out with SAS. After this step, the goodie text is stored in the GOODIE macro variable.
/* Assuming this is run on Friday */ %let day = %sysfunc(compress(%sysfunc(today(),yymmdd10.),'-')); filename bg "../menus/DailyMenus/BreakfastWeb&day..html"; data _null_; infile bg dsd; length line $ 80 goodie $ 40; input line; /* Line with the goods */ if (find(line,'span class="entryName"') >0) then do; startpos = find(line, '>'); endpos=find(line, '</'); goodie = substr(line,startpos+1,endpos-startpos-1); call symput('GOODIE',goodie); end; run; |
Sending the SMS message with SAS
Finally, we're getting to the part of this article that you probably came to read: how to send the text message with SAS. This feels a bit like cheating, but there isn't any magic function in SAS that sends SMS messages. Instead, we're going to rely on a mobile phone service trick. Most phone service providers allow you to send text messages via e-mail by using a special address scheme for the text message recipient. Each carrier is a little different, but you can find the details with a simple internet search: "sms via email".
RECOMMENDED SAS TIP | HOW TO SEND EMAIL USING SASMy current carrier is AT&T, and so to receive a text message as e-mail I would send it to the address my_number@txt.att.net. With the FILENAME EMAIL method, it's easy to send an e-mail using SAS. The trickiest part might be to find your SMTP server host name and other details. Using a service like Gmail? I've written a blog post about how to send e-mail with that method. Note: as with all phone text messages, text-message charges from your carrier may apply.
options emailhost='mailserver.company.com' emailsys=smtp; /* NOT my real phone number */ filename msg email to="9198675309@txt.att.net" FROM = "Cafe Bot <youremail@company.com>" subject="Breakfast goodie: &Goodie."; data _null_; file msg; put 'Bon appetit!'; run; |
Here's an example of the text message from my phone:
"Blueberry Almond Crunch Teacake" - yum! I'm skipping the Cheerios this morning and taking breakfast at work instead.
Scheduling the SAS job to run automatically
This entire process is valuable only if we can run it unattended, without having to remember to trigger it every Friday morning. After all, if you can log in to run a SAS job that sends yourself a text message, you can (probably more easily) just check the breakfast menu for the day. So my colleague scheduled this program to run early every Friday morning at SAS using a cron job, the ubiquitous scheduler on UNIX. I imagine that his crontab -l output looks something like:
00 05 * * 5 /usr/local/bin/sas -nodms -sysin '/u/userid/food/breakfastgoodie.sas'
That sets up the job to run at 05:00 on day 5 (Friday), running SAS with this program as input. In the immortal words of Ron Popeil: Set it, and forget it!
25 Comments
Chris,
Great tip and fun write-up! Now, I'm itching to find a similar use for it here at Westat.
----MMMMIIIIKKKKEEEE
Time to institute a free Friday breakfast there in Rockville!
A masterly trick this is! The SAS is STRONG with this one...
Programmer planning! Love it. Makes the breakfast goodie even sweeter!
LOVE THIS - I can have a text message sent with weather info so I'll know if I should ride the Harley or drive the car to work!
Brilliant! Thanks for sharing!
Good one Chris.. :)
Funny! I did this last Tuesday when school started. I scheduled morning texts to my kids to let them know how many days of school are left in this school year.
#DataForGoodie? :)
You said it, not me. I would never encroach on hashtag like that.
I see you added a comment in the code that 919-867-5309 is *not* your phone number. I guess SAS programmers need to be of a certain vintage to know that you used Jenny's phone number in your example. :-)
Suzanne, feel free to call it if you're looking for a good time. No promises though!
Great tip.
How can I expand it to loop to do the following at the same time?
1. send it to a list of people
2. have a variable message
(Sorry, trying to learn!)
Great question. Let's assume that you have a distribution list in an external file named 'dist.csv'. You can read that file and create a dynamic TO list like this:
filename dl "/u/user/proj/dist.csv"; data distlist; infile dl dsd; length email $ 50; input email; run; /* build list like: 'email1' 'email2' 'email3' etc */ proc sql noprint; select cat('"',trim(email),'"') into :toList separated by ' ' from distlist; quit; FILENAME OUTPUT EMAIL SUBJECT = "your subject" FROM = "youremail@whatever.com" TO = (&toList) ;
Hi, Chris,
Thank you for your quick code.
Does your code handle varying messages? I am a very basic SAS programmer.
We are trying to write a program that reads a input file each day and creates a message (alert) when certain conditions are found; there could be many messages/alerts created each day. The message/alert is then supposed to trigger an email (or text) to the primary on-call, secondary on-call, and the manager.
Gratefully,
Perry
Perry,
You can easily vary the message. Build it conditionally in the DATA step, or pull it in from different files depending on the situation. Your SAS code can check for a file, a data set, a macro variable -- whatever you want. The FILENAME EMAIL method also has a lot of options for various types of e-mail. Check out the examples in the doc.
Hi, Chris,
Your guidance is greatly appreciated.
Our user just changed the requirements again. Although the process above is no longer necessary, I hope to still work on it on my own, to learn and maybe use it in the future.
Sincere thanks,
Perry
Maybe you can program SAS to send e-mail every time the user requirements change. If your e-mail system can handle that volume!
How to send a text message to cell phone when report finished running? Please explain?
Srinidi
Catch Experts
Hi Srinidi, Not sure I understand the question? The FILENAME EMAIL step, using the trick to send a text via e-mail, is what completes the action. If you're stuck and have an example error/SAS log, post back.
Hi Chris,
Have you also considered a traditional REST API connection to A2P SMS providers Vs. free email gateways as a means of getting text messages into and from SAS. Granted there is a cost to sending SMS in this capacity however commercially deployed applications will generally need a level of functionality and reliability that the email gateways do not provide. It's a bit self serving but traditional REST integrations to 3rd party providers allow for 2-way communications, message status/delivery receipts, click analysis, etc., and most importantly SLAs and compliance. Commercial services such critical alerts, one-time passcodes and customer engagement will generally require the uptime guarantees and accountability provided by these types of platform providers.
Best,
Ben
Hi, I'll allow your "self serving" comment because it's a good opportunity to point out that SAS can publish content via REST APIs -- plenty of examples on this blog, including this one about Slack channels. If a SAS customer uses a 3rd party service to publish content to lots of recipients, it can certainly be automated in code.
Thanks for this. For Comcast/Xfinity I needed to change it to MMS code to get it to work.
Pingback: How to publish to a Microsoft Teams channel using SAS - The SAS Dummy
Hi Chris, Nice article there, I'm actually interested in SAS. Where to start learning?
I recommend starting here at the Learn SAS site, where you can find free courses, path to certification, and more.