BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
freshstarter
Quartz | Level 8

Hello,

 

Currently, we have configured an Azure app (Microsoft Graph) to send emails from our SAS Viya environment using SAS code. I am able to successfully send emails using this code.

However, the issue is that I can only send an email to a single email address. I am unable to specify multiple email addresses in the To field with the current code. I am struggling to update the code logic to support multiple recipients.

Could you please help me with this?

 

%macro send_graph_mail(
    to=,
    cc=,
    subject=,
    body=
);

    %local access_token has_cc CLIENT_ID CLIENT_SECRET TENANT_ID;
    %let has_cc = %sysfunc(ifc(%length(&cc) > 0, 1, 0));

    %let CLIENT_ID     = xxxxxxx;
    %let CLIENT_SECRET = xxxxxxx;
    %let TENANT_ID     = xxxxxxx;

    /*--------------------------------*/
    /* Get OAuth token                */
    /*--------------------------------*/
    filename resp temp;

    proc http
        url="https://login.microsoftonline.com/&TENANT_ID/oauth2/v2.0/token"
        method="POST"
        in="grant_type=client_credentials%str(&)
            client_id=&CLIENT_ID%str(&)
            client_secret=&CLIENT_SECRET%str(&)
            scope=https://graph.microsoft.com/.default"
        ct="application/x-www-form-urlencoded"
        out=resp;
    run;

    libname auth json fileref=resp;

    data _null_;
        set auth.root;
        call symputx('access_token', access_token );
    run;

    /*--------------------------------*/
    /* Build mail JSON                */
    /*--------------------------------*/

    filename mail temp;

    data _null_;
        length subject_txt body_txt addr $1000;
        file mail lrecl=32767;

        subject_txt = strip(symget('subject'));
        body_txt    = strip(symget('body'));

        subject_txt = tranwrd(subject_txt, '"', '\"');
        body_txt    = tranwrd(body_txt,    '"', '\"');

        addr = strip(symget('to'));

        put '{';
        put '  "message": {';
        put '    "subject": ' '"' subject_txt '"' ',';
        put '    "body": {';
        put '      "contentType": "Text",';
        put '      "content": ' '"' body_txt '"' ;
        put '    },';
        put '    "toRecipients": [';
        
        
        addr = symget('to');
        addr = strip(addr);
        addr = left(addr);


        put '      { "emailAddress": { "address": "' addr +(-1) '" } }';
        put '    ]';
        put '  }';
        put '}';
    run;

    /*-----------------------------*/
    /* Send email                  */
    /*-----------------------------*/
    filename sendresp temp;
    
    proc http
        url="https://graph.microsoft.com/v1.0/users/&SENDER_EMAIL/sendMail"
        method="POST"
        in=mail
        out=sendresp;
        headers
        "Authorization"="Bearer &access_token"
        "Content-Type"="application/json";
    run;

%mend;

data _null_;
    format dte ddmmyy10. tme time8.;
    dt = datetime();
    call symputx(
        'mail_body',
        cats(
            'Hello,', 
            'The scheduled job completed successfully at ',
            put(datepart(dt), ddmmyy10.), ' ',
            put(timepart(dt), time8.), 
            'Thank you', 
            'Platform Support Team'
        ),
        'L'
    );
run;


%send_graph_mail(
    to=fresh.starter@org.com,
    subject=Test SAS Completed Successfully,
    body=%superq(mail_body)
);
1 ACCEPTED SOLUTION

Accepted Solutions
Quentin
Super User

This is not a complete answer, but you'll need to add some looping to generate the json array of email addresses.  

 

You could try replacing your current line:

put '      { "emailAddress": { "address": "' addr +(-1) '" } }';

With a macro loop like below:

  %local i ;
  %do i=1 %to %sysfunc(countw(&to,%str( ))) ;
    %if &i>1 %then %do ;
      put "," ;
    %end ;
    put "      { ""emailAddress"": { ""address"": ""%scan(&to,&i,%str( ))"" } }";
  %end ;

That would allow you to pass a space-delimited list of email addresses.

The Boston Area SAS Users Group is hosting free webinars!

Register now at https://www.basug.org/events.

View solution in original post

3 REPLIES 3
Quentin
Super User

This is not a complete answer, but you'll need to add some looping to generate the json array of email addresses.  

 

You could try replacing your current line:

put '      { "emailAddress": { "address": "' addr +(-1) '" } }';

With a macro loop like below:

  %local i ;
  %do i=1 %to %sysfunc(countw(&to,%str( ))) ;
    %if &i>1 %then %do ;
      put "," ;
    %end ;
    put "      { ""emailAddress"": { ""address"": ""%scan(&to,&i,%str( ))"" } }";
  %end ;

That would allow you to pass a space-delimited list of email addresses.

The Boston Area SAS Users Group is hosting free webinars!

Register now at https://www.basug.org/events.
freshstarter
Quartz | Level 8

Thank you so much @Quentin .it worked.

 

But when I update the same code for cc Recipients, it throws me an error message. 

 

{"error":{"code":"BadRequest","message":"Unable to read JSON request payload. Please ensure Content-Type header is set and payload i
s of valid JSON format.","innerError":{"date":"2026-04-28T21:17:39","request-id":"xxxx","client-request-id":"xxxx"}}}
%macro send_graph_mail(
    to=,
    cc=,
    subject=,
    body=
);

    %local access_token has_cc CLIENT_ID CLIENT_SECRET TENANT_ID;
    %let has_cc = %sysfunc(ifc(%length(&cc) > 0, 1, 0));

    %let CLIENT_ID     = xxxxxxxxxxxxxxxxxxxxx;
    %let CLIENT_SECRET = xxxxxxxxxxxxxxxxxxxxx;
    %let TENANT_ID     = xxxxxxxxxxxxxxxxxxxxx;

    /*--------------------------------*/
    /* Get OAuth token                */
    /*--------------------------------*/
    filename resp temp;

    proc http
        url="https://login.microsoftonline.com/&TENANT_ID/oauth2/v2.0/token"
        method="POST"
        in="grant_type=client_credentials%str(&)
            client_id=&CLIENT_ID%str(&)
            client_secret=&CLIENT_SECRET%str(&)
            scope=https://graph.microsoft.com/.default"
        ct="application/x-www-form-urlencoded"
        out=resp;
    run;

    libname auth json fileref=resp;

    data _null_;
        set auth.root;
        call symputx('access_token', access_token );
    run;

    /*--------------------------------*/
    /* Build mail JSON                */
    /*--------------------------------*/

    filename mail temp;

    data _null_;
        length subject_txt body_txt addr $1000;
        file mail lrecl=32767;

        subject_txt = strip(symget('subject'));
        body_txt    = strip(symget('body'));

        subject_txt = tranwrd(subject_txt, '"', '\"');
        body_txt    = tranwrd(body_txt,    '"', '\"');

        addr = strip(symget('to'));

        put '{';
        put '  "message": {';
        put '    "subject": ' '"' subject_txt '"' ',';
        put '    "body": {';
        put '      "contentType": "HTML",';
        put '      "content": ' '"' body_txt '"' ;
        put '    },';
        put '    "toRecipients": [';
        
        
        %local i ;
        %do i=1 %to %sysfunc(countw(&to,%str( ))) ;
        %if &i>1 %then %do ;
        put "," ;
        %end ;
        put "      { ""emailAddress"": { ""address"": ""%scan(&to,&i,%str( ))"" } }";
        %end ;
        put '    ]';

        put '    "ccRecipients": [';      
        %local j ;
        %do j=1 %to %sysfunc(countw(&cc,%str( ))) ;
        %if &j>1 %then %do ;
        put "," ;
        %end ;
        put "      { ""emailAddress"": { ""address"": ""%scan(&cc,&j,%str( ))"" } }";
        %end ;
        put '    ]';
      
        put '  }';
        put '}';
    run;

    /*-----------------------------*/
    /* Send email                  */
    /*-----------------------------*/
    filename sendresp temp;

    proc http
        url="https://graph.microsoft.com/v1.0/users/&SENDER_MAIL/sendMail"
        method="POST"
        in=mail
        out=sendresp;
        headers
        "Authorization"="Bearer &access_token"
        "Content-Type"="application/json";
    run;

    
data _null_;
    infile sendresp;
    input;
    putlog _infile_;
run;

%mend;

data _null_;
    format dte ddmmyy10. tme time8.;
    dt = datetime();

    call symputx(
        'mail_body',
        catx(
            '',
            '<html><body>',
            '<p>Hello,</p>',
            '<p>The scheduled job completed successfully on ',
            put(datepart(dt), ddmmyy10.),
            ' at ',
            put(timepart(dt), time8.),
            '.</p>',
            '<p>Thank you,<br>',
            'Platform Support Team</p>',
            '</body></html>'
        ),
        'L'
    );
run;


%send_graph_mail(
    to=fresh.starter@org.com freshstarter@gmail.com,
    cc=fresh.starter@org.com,
    subject=Test SAS Extract Completed Successfully,
    body=%superq(mail_body)
);
freshstarter
Quartz | Level 8

It is working now. I have missed a comma, Thanks for the support

 

%if &has_cc %then %do;
    put '   , "ccRecipients": [';      
    %do j=1 %to %sysfunc(countw(&cc,%str( ))) ;
        %if &j>1 %then %do ;
            put "," ;
        %end ;
        put "      { ""emailAddress"": { ""address"": ""%scan(&cc,&j,%str( ))"" } }";
    %end ;
    put '    ]';
%end;

Catch up on SAS Innovate 2026

Dive into keynotes, announcements and breakthroughs on demand.

Explore Now →
How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 3 replies
  • 313 views
  • 2 likes
  • 2 in conversation