Hi, I am have a program that is supposed to send out different email messages based on whether a certain condition is met. I have created strings of all my variables to feed them through a do loop to send out each individual email. I have successfully created the string of variables, but can't seem to figure out how to call them in my email code. I am not sure whether I can call macro variables using a put statement in another macro. I have my code below, any help is much appreciated!
proc sql noprint;
select SUBJECT, EMAIL, BODY1, count(SUBJECT)
into
:SUBJECT separated by '|',
:EMAIL separated by '|',
:BODY1 separated by '|',
:n
from all;
quit;
%put subject=&subject;
options emailsys=XX emailhost='XXX.XXXX.com' emailauthprotocol=none emailid="XXXXXXXXXXXXXX.com" ;
options mprint;
%macro email;
%do i=1 %to &n;
%let SUBJECT=%scan(&SUBJECT,&i,'|');
%let EMAIL=%scan(&EMAIL,&i,'|');
%let BODY1=%scan(&BODY1,&i,'|');
%macro sendemail;
*write an email;
filename outbox email;
data _null_;
file outbox
to=("XXXXXX.com")
subject="&EMAIL";
put "&body1";
put ' ';
put 'SUBJECT:&SUBJECT';
put ' ';
put 'Thanks,';
run;
filename outbox clear;
%mend;
%sendemail;
%end;
%mend;
%email;
Hi Reeza, I'm not exactly sure what you mean, you could write out a sample of what you mean? Thank you!
basically this idea.
https://github.com/statgeek/SAS-Tutorials/blob/master/Turning%20a%20program%20into%20a%20macro.md
It seems you already have your data in a dataset since you're using that to create macro variables.
Instead, change your macro program to send an email provided the body, subject and email parameters.
%macro emailClients(email=, subject=, body=);
....code ...
%mend;
Now, like in my example linked, call that macro from your data set.
data test;
set all;
str = catt('%emailClient(email=', email, ', subject=', subject, ',body=', body, ');');
if run='Y' then call execute(str);
run;
I usually keep it in a data set so I can check that the str variable is created correctly and once that's verified, I change it to a data _null_ step so that it's cleaner.
Hi Reeza, I see what you mean. The only reason I think this might not work for my specific program is because the emails are generated based on certain conditions. So I won't know when one email is generated over another. Which is why I thought it would be easier to just create a string of each variable and just run the do loop through them (because the email body/subject/ etc might be different) I hope that makes sense, thank you again for all the help on this!
While I agree with @Reeza that you are using more macro language than I would, you could keep your current program. However, there is a laundry list of issues to consider.
Beyond that, you didn't tell us what went wrong. Why do you say it isn't working? What did the log show?
So when the macros are not used, I can successfully send an email, but it will only send an email for the last subject in the dataset, which is why I was trying to create a do-loop to get separate emails sent for each subject.
I tried removing the quotations for '|' but it gave me an error, I have checked that the strings for all those variables were successfully created, so I think this part of the code is working ok.
What ends up happening though, is the multiple emails are sent correctly, but they only include the text I have written out in the email, none of the actual macro values are recognized. Only the very first email is correct and has all the information, so it is something with my do loop
EMAIL EXAMPLE:
subject= (no subject shows up)
''
''
SUBJECT:
Thanks,
It seems like my do loop is not running past n=1 for some reason
Perhaps this will give you some ideas?
https://github.com/scottbass/SAS/blob/master/Macro/sendmail.sas
I see, what would be the alternative though? Because I thought using the scan function was necessary to go through the string of values that I created for each variable.
First, use the "little running man" button for posting code, so we don't get smileys and scrambled code formatting.
Second, NEVER define macros inside each other. This serves NO purpose at all, as all macros are defined in the global symbol table, and only clutters up the definition of the outside macro, making it less readable and maintainable.
Third, there's no need to intermediately store lists in macro variables from a dataset when you can directly execute your code from that dataset:
%macro sendemail(email=,body1=,subject=);
*write an email;
filename outbox email;
data _null_;
file outbox
to=("XXXXXX.com")
subject="&EMAIL"
;
put "&body1";
put ' ';
put "SUBJECT:&SUBJECT";
put ' ';
put 'Thanks,';
run;
filename outbox clear;
%mend;
data _null_;
set all;
call execute(cats('%nrstr(%sendmail(email=',email,',body1=',body1,',subject=',subject,'))'));
run;
Here, I only used the macro definition to make the call execute shorter. In RL, I usually put the code right into the data step like this:
data _null_;
set all;
call execute('
filename outbox email;
data _null_;
file outbox
to=("XXXXXX.com")
subject="' !! EMAIL !! '"
;
put "' !! strip(body1) !!'";
put " ";
put "SUBJECT:' !! strip(SUBJECT) !! '";
put " ";
put "Thanks,";
run;
filename outbox clear;
');
run;
Note that the subject would not have worked in your original code because of the single quotes.
Hi, I am have a program that is supposed to send out different email messages based on whether a certain condition is met.
You don't really go into enough detail on this. What condition? And what's supposed to happen when that condition is met? Does the Subject change? The To: list change? Is the email body the same, just the subject is different? You know you can put more than one address in the To: list, right? You don't have to send separate emails one at a time.
In addition to my previous sendmail link, perhaps these will help. Read the macro header for use cases:
https://github.com/scottbass/SAS/blob/master/Macro/loop.sas
https://github.com/scottbass/SAS/blob/master/Macro/loop_control.sas
For example, with loop_control, you could create a metadata dataset with your To, Subject, Body, etc, plus some filtering condition. Then call your child macro, filtering your control table with a where clause.
Thank you, that worked perfectly and exactly how I needed!
Thank you to everyone for their help on this. I need to keep working on the proper way of coding macros...still learning.
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.