Email not being sent and there is no error [SAS] - email

%let emailUsername = %scan(&sysparm,1,+);
%let email = %unquote(%str(&emailUsername.#example.com));
%let sasProgram = %scan(&sysparm,2,+);
%let todayDate = %sysfunc(today(),MMDDYYS10.);
%let timeNow = %sysfunc(time(),TIMEAMPM.);
FILENAME mail
EMAIL TO=%unquote(%str(%'&email.%'))
SUBJECT='SAS Job Complete: &todayDate. on &timeNow.'
CONTENT_TYPE="text/html";
DATA _NULL_;
file mail;
PUT "<body>";
PUT "<p>Hello,</p>";
PUT "<p>This is an email confirming that your SAS program [&sasProgram..sas] has successfully ran and finished.</p>";
PUT "<p>- Creators of the SAS Program</p>";
PUT "</body>";
Run;
I am trying to understand why an email is not being sent. If I hard code the email address in, it works but when I have variables passed through it doesn't work. There is no error in the log file in regards to me trying to send an email so I am assuming it was successful.
Is there something else I need to do or look at?

Here is what I did, I changed your userEmail assignment and it's working:
%let emailUsername = psamson6;
%let email = %unquote(%str(&emailUsername.#gmail.com));
%let sasProgram = %scan(&sysparm,2,+);
%let todayDate = %sysfunc(today(),MMDDYYS10.);
%let timeNow = %sysfunc(time(),TIMEAMPM.);
FILENAME mail
EMAIL TO=%unquote(%str(%'&email.%'))
SUBJECT='SAS Job Complete: &todayDate. on &timeNow.'
CONTENT_TYPE="text/html";
DATA _NULL_;
file mail;
PUT "<body>";
PUT "<p>Hello,</p>";
PUT "<p>This is an email confirming that your SAS program [&sasProgram..sas] has successfully ran and finished.</p>";
PUT "<p>- Creators of the SAS Program</p>";
PUT "</body>";
Run;

Related

Convert datetime (e.g. 01JAN2020) to date format (e.g 01/01/2020) in SAS

I have a bunch of datetime formatted values in my dateset that started in the format 01JAN2020:00:00:00. I've managed to condense this down using dtdate9. but that changes the format to 01JAN20. I'm looking to change the format to 01/01/2020, any ideas?
As far as I know, there is no off the shelf SAS format that maps a datetime value to construct mm/dd/yyyy.
You can create a user defined function with FCMP that computes the transform and specify that function in a custom format.
Example:
proc fcmp outlib=work.functions.formats;
function dtmmddyy(datetime) $10;
return (put(datepart(datetime), mmddyy10.));
endsub;
run;
proc format;
value dtmmddyy
low-high = [dtmmddyy()]
;
run;
options cmplib=(work.functions);
data _null_;
dt = input ('01JAN2020:00:00:00', datetime20.);
put
dt= dtdate9. /
dt= dtmmddyy. /
;
run;
Log
dt=01JAN2020
dt=01/01/2020
You can write a custom datetime type format like this
proc format;
picture dtdmy (default=10)
low - high = '%D/%0m/%Y' (datatype=datetime)
;
run;
data _null_;
dt = '01JAN2020:00:00:00'dt;
put dt = dtdate9.;
put dt = dtdmy.;
run;
You can also control it via the length on a date time format, especially if it's only for display, at least if it's MDY. Not sure about DMY formats.
data demo;
have = dhms('01Jan2020'd, 4, 3, 0);
x = have;
format x mdyampm10. have datetime22.;
run;
1 01JAN2020:04:03:00 1/1/20

SEND EMAIL BASED ON CONDITIONS (SAS)

I found the below code (untouched) in this forum which is very close to what i was looking for however am having some issues when tweaking;
data Millenium_Falcon;
han='1';
luke='0';
darth='0';
run;
filename myemail EMAIL
to="me#lando.com"
cc="me#lando.com"
from="me#lando.com"
subject="Millenium Falcon"
importance="HIGH"
;
data _null_;
set Millenium_Falcon ;
file myemail;
IF (Luke = '1' and Darth = '0') then do;
put "Han,";
put " ";
put "Look out for the asteroids.";
put " ";
put "Thank you.";
put " ";
put "Obi";
end;
else do;
put '!EM_ABORT!';
end;
stop;
run;
Before tweaking, this code works fine however when i try to point to my data set (removing Millennium_Falcon step above) which just contains meta data from dictionary.tables (libname,memname,modate) and change the if statement to
IF (memname = 'TEST' and datepart(modate) = date()) then do;
the email does not send. It is almost like the data step (below) must be present (acting like datalines) for this to work.
data Millenium_Falcon;
han='1';
luke='0';
darth='0';
run;
Any help would be much appreciated.
Many thanks
Aaron
You probably want something more like this that will abort when no records meet the criteria and otherwise generate a list of the values that do.
data _null_;
file myemail;
if _n_=1 and eof then put '!EM_ABORT!';
set have end=eof ;
where (memname = 'TEST' and datepart(modate) = date()) ;
put memname= modate= ;
run;

SAS - Fill in null values for numeric variables but not dates

I use the following to fill in null values for numeric variables with 0, but this does it for date variables as well. How can I fill in null values only for non-date numeric variables?
data mydataset;
set mydataset;
array myarray _numeric_;
do over myarray;
if myarray=. then myarray=0;
end;
run;
There is an excellent post on SAS Communities about determining if a variable is a date or not. It's available here. Your question isn't trivial, as you shouldn't forget about user-defined formats which can also behave like date formats (proc format). Let's suppose that all your date variables are of one format.
data test;
format x y z datetime8.;
x = .;
y = .;
z = .;
run;
%macro get_vars_format(lib, tab, fmt);
proc sql noprint;
select name into :names separated by ' '
from sashelp.vcolumn
where libname = "&lib." and
memname = "&tab." and
format eq "&fmt.";
quit;
%put Names: &names.;
data work.test;
set &lib..&tab.;
%let i = 1;
%let name = %scan(&names., &i., %str( ));
%do %while(&name. ne );
if &name. eq . then &name = 0;
output;
%let i = %eval(&i + 1);
%let name = %scan(&names., &i., %str( ));
%end;
run;
%mend get_vars_format;
%get_vars_format(lib=WORK, tab=TEST, fmt=DATETIME8.);
This macro takes three arguments:'
library name,
data set name,
and desired format name.
I am saving all the variables names into a macro-variable (they are separated by a space sign) and in a next step, I am iterating this in a loop (note i and name macro-variables). For every row, if a value of any variable with a given format is equal to . then replace it with 0. Note that if a variable has a date format, 0 will be treated as a Jan 01, 1960, as that's the first day in SAS date value convention.

Formatting output in powershell

I'm attempting to write a powershell script and running into a problem that google can't seem to tell me how to fix. Basically, i have 4 variables:
$myDuration = $myObj.Duration
$mySubject = $myObj.Subject
$myStart = $myObj.Start
$myLocation = $myObj.Location
I'm trying to send an email where the body is:
"Your meeting ({0}) will begin {1}. It will be held at {2} and last approximately {3}." -f $mySubject,$myStart,$myLocation,$myDuration
Now, if I ONLY include one variable, it works just fine. For example, "Your meeting {0}" -f $myLocation correctly outputs the value stored in $myLocation.
WHen I include more then one, my output for each variable is the exact string "System.Object[]". (IE "Your meeting (System.Object[]) will begin System.Object[]. It will be held at System.Object[] and last approximately System.Object[].") Any ideas why it bugs when I include more then one variable? From everything I've read about on Google there shouldn't be an issue.
Thank you for your time. Editing for hopefully better clarification of my issue.
I suspect that one or more of the fields in $myObj is something other than a string and can't be converted to a string easily, and that's throwing the formatter off. Have a look at this code:
$myDuration = "Duration";
$mySubject = "Subject";
$myStart = "Starttime";
$myLocation = "Location";
"Your meeting ({0}) will begin {1}. It will be held at {2} and last approximately {3}." -f $mySubject,$myStart,$myLocation,$myDuration
$myObj = #{"Duration"=[int32]123456;"Subject"="Subject2";"Starttime"=(get-date);"Location"="Location2"};
$myDuration = $myObj.Duration;
$mySubject = $myObj.Subject;
$myStart = $myObj.Starttime;
$myLocation = $myObj.Location;
"Your meeting ({0}) will begin {1}. It will be held at {2} and last approximately {3}." -f $mySubject,$myStart,$myLocation,$myDuration
And my output is:
Your meeting (Subject) will begin Starttime. It will be held at Location and last approximately Duration.
Your meeting (Subject2) will begin 2/13/2014 10:30:39 PM. It will be held at Location2 and last approximately 123456.
It all works as expected.

SAS Reading multiple records from one line without Line Feed CRLF

I have only 1 line without line feed (CRLF CRLF), the linefeed is a string of 4 characters, in this example is "#A$3" I don't need dlm for now, and I need to import it from a external file (/files/Example.txt)
JOSH 30JUL1984 1011 SPANISH#A$3RACHEL 29OCT1986 1013 MATH#A$3JOHNATHAN 05JAN1985 1015 chemistry
I need this line into 3 lines:
JOSH 30JUL1984 1011 SPANISH
RACHEL 29OCT1986 1013 MATH
JOHNATHAN 05JAN1985 1015 chemistry
How I can do that in SAS?
*Added: Your solutions are working with this example, but i have a issue, a line that contains more than the maximum length allowed for the line(32,767 bytes),
For example this line in the above exercise contains 5,000 records.
Is it possible?
Use the DLMSTR= option on the infile statement -- this will specify "#A$3" as the delimiter. Then use ## on the input statement to tell SAS to look for more records on the same line.
data test;
infile "/files/Example.txt" dsd dlmstr='#A$3';
informat var $255.;
input var $ ##;
run;
With your example, you will get a data set with 3 records with 1 variable containing the strings you are looking for.
Adjust the length of var as needed.
You could do something like this:
First import the file as a single row (be sure to adjust the length):
DATA WORK.IMPORTED_DATA;
INFILE "/files/Example.txt" TRUNCOVER;
LENGTH Column1 $ 255;
INPUT #1 Column1 $255.;
RUN;
Then parse imported data into variables using a data step:
data result (keep=var1-var4);
set WORK.IMPORTED_DATA;
delim = '#A$3';
end = 1;
begin = 1;
do while (end > 0);
end = find(Column1, delim, begin);
row = substr(Column1, begin, end - begin);
var1 = scan(row, 1);
var2 = scan(row, 2);
var3 = scan(row, 3);
var4 = scan(row, 4);
begin = end + length(delim);
output;
end;
run;
Try this in data step by viewing #A$3 as a multi-character delimiter:
data want (keep=subject);
infile 'C:\sasdata\test.txt';
input;
length line $4500 subject $80;
line=tranwrd(_infile_,"#A$3",'!');
do i=1 by 1 while (scan(line,i,'!') ^= ' ');
subject=scan(line,i,'!');
output;
end;
run;
_infile_ gives the current row that is being read in the data step. I converted the multi-character delimiter #A$2 into a single-character delimiter. tranwrd() can replace a sub-string inside a string. And then use the delimiter inside the scan() function.
Also, if you want to break the values up into separate variables, just scan some more. E.g. put something like B = scan(subject,2); into do loop and data want (keep= A B C D);. Cheers.