• Inicio
  • Novedades
  • Academia SAP
  • FAQ
  • Blog
  • Contacto
S4PCADEMY_Logo
Twitter Linkedin Instagram
S4PCADEMY_Logo
Twitter Linkedin Instagram
FORMACIÓN SAP

Integración en la nube: envíe correo a través de la API de Microsoft Graph con el código de autorización de OAuth 2.0

By s4pcademy 


El blog «Integración en la nube: conéctese a Microsoft 365 Mail con OAuth2contiene capítulos sobre cómo puede conectarse desde SAP Cloud Integration a Microsoft 365 a través de OAuth2 para enviar correos utilizando el protocolo SMTP. En este blog describimos una alternativa al protocolo SMTP: usamos Microsoft Graph DESCANSAR API para enviar correos utilizando el adaptador de receptor http de SAP Cloud Integration.

Creamos un flujo de integración que se conecta a la API REST de Microsoft Graph descrita en https://learn.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http.

Al conectarse a Outlook 365 con OAuth2, debe tener un directorio organizativo/inquilino en Microsoft Azure Active Directory y un usuario en este directorio que tenga una suscripción a Outlook 365. La siguiente captura de pantalla muestra un ejemplo de dicho usuario en Azure Active Directory con nombre “testusermail” que tiene la licencia “Exchange Online (Plan1)”.

Puede comprobar si el usuario tiene una suscripción a Outlook 365 iniciando sesión con el usuario en https://outlook.office365.com/mail/.

Para las tareas de configuración en Azure Active Directory, también necesita un usuario con el rol de «Administrador de aplicaciones» y «Desarrollador de aplicaciones».

Además, necesita un inquilino de SAP Cloud Integration o Integration Suite en el que tenga un usuario con el rol de «Desarrollador de integración».

Creamos un flujo de integración al que puede llamar a través de un cliente HTTP y que se conecta a Microsoft Graph a través del adaptador receptor HTTP de SAP Cloud Integration. Para configurar este escenario, ejecute los siguientes pasos:

  • Paso 1: determinar el URI de redireccionamiento
  • Paso 2: Crear cliente/aplicación OAuth en Microsoft Azure Active Directory
  • Paso 3: cree una credencial de código de autorización OAuth2 en su arrendatario de SAP Cloud Integration
  • Paso 4: Cree una colección de guiones con un guión maravilloso
  • Paso 5: Cree un flujo de integración con un paso de script y un adaptador de receptor HTTP
  • Paso 6: Ejecutar el Flujo de Integración

Cuando inicia sesión en SAP Cloud Integration o Integration Suite WEB-UI, ve su nombre de host en el campo de dirección del navegador:

https://<host name>/itspaces (for Cloud Integration)

https://<host name>/shell/home (for Integration Suite)

Utilice el para construir el siguiente URI de redireccionamiento:

Necesita este URI de redireccionamiento en el siguiente paso.

  1. Inicie sesión en su inquilino de Azure usando https://portal.azure.com/
  2. Seleccione «Registros de aplicaciones» en «Servicios de Azure».
  3. Haga clic en «Nuevo registro», proporcione un nombre para su aplicación, elija en el menú desplegable «Seleccione una plataforma» el valor «Web“, e ingrese el URI de redireccionamiento determinaste al principio. No cambie la configuración predeterminada para los «tipos de cuenta» («Cuentas en este directorio organizacional solamente»). Después de eso, seleccione «Registrarse».

Guarde la ID de la aplicación (cliente) en cualquier lugar de su escritorio local. Necesitará este ID más tarde para configurar la credencial OAuth2 en CPI.

4. Elija «Certificados y secretos» en el menú de la izquierda.

5. Selecciona “Nuevo secreto de cliente”, elige el periodo de caducidad que prefieras (“En 1 año”, “En 2 años” o “Nunca”). Opcionalmente, también puede agregar una descripción. Cuando haya terminado, seleccione «Agregar».

Observación: antes de que caduque el secreto, debe crear un nuevo secreto y transferir el nuevo secreto a la credencial del código de autorización SAP CPI OAuth2 (consulte a continuación).

6. Use el botón «Copiar al portapapeles» para recordar el secreto creado (lo necesitará más adelante para configurar la credencial OAuth2 en CPI).

7. Vuelva a la vista «Descripción general» de la aplicación y seleccione la pestaña «Puntos finales».

Copie el «punto final de autorización de OAuth 2.0 (v2)» y el «punto final de token de OAuth 2.0 (v2)» en su escritorio local. Necesitará estos valores más adelante para la creación de la credencial OAuth2 en Cloud Integration.

8. Elige “Permisos API” en el menú de la izquierda y comprueba que está configurado el permiso “Microsoft Graph User.Read”. Este permiso debería estar ahí por defecto. Si no, entonces agréguelo.

Inicie sesión en su inquilino de Cloud Integration a través de la URL https:///itspaces (para Cloud Integration) o la URL https:///shell/home (para Integration Suite). Cambie a la «Vista de operaciones» (presione el icono del ojo) y seleccione el mosaico «Materiales de seguridad». Seleccione el botón «Crear» y elija «Código de autorización OAuth2».

Ingrese un nombre para la credencial y la «URL de autorización», «URL de servicio de token», «ID de cliente» y «Secreto de cliente» de su aplicación de Microsoft.
Introduzca también un «Nombre de usuario». Esta es la dirección de correo electrónico del usuario a cuyos recursos de correo desea acceder en un flujo de integración. Este usuario debe existir en el mismo directorio/inquilino de Microsoft Azure que la aplicación creada y debe tener una cuenta de Outlook 365.

Ingrese el alcance “https://graph.microsoft.com/Mail.Send”

Además, necesita el alcance «offline_access» para crear tokens de actualización (si no se agrega este alcance, SAP Cloud Integration agregará este alcance automáticamente). Los ámbitos deben estar separados por un espacio.

El valor predeterminado para el vencimiento del token de actualización se establece en 90 días para «Microsoft 365» (ver: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-configurable-token-lifetimes). Sin embargo, si se cambió el tiempo de vencimiento para su arrendatario de Microsoft, ajuste este valor.

Después de hacer clic en el botón «Implementar», verá la credencial «Código de autorización OAuth2» recién creada en la lista de Materiales de seguridad en estado «No autorizado“.

Seleccione los tres puntos en la entrada con la credencial creada y elija la opción «Autorizar».
Aparecerá una ventana emergente de confirmación. Selecciona “Continuar”:
Aparece una pantalla de inicio de sesión de Microsoft. Ingrese la contraseña del usuario que especificó en la credencial OAuth2:

Después de seleccionar «Iniciar sesión», aparece otra ventana emergente que indica los permisos solicitados que requiere la aplicación:

Seleccione «Aceptar». Debería recibir un mensaje de éxito:

Regrese a la página anterior del navegador y actualice la lista de Materiales de seguridad (botón «Recargar contenido»). El estado de la credencial «Código de autorización OAuth2» cambió a «Implementado»:

El siguiente guión de Groovy es la parte más importante de nuestro escenario. Groovy Script obtiene el token de acceso de OAuth2 del servidor de identidad de Microsoft y crea el cuerpo de la solicitud HTTP para enviarlo a Microsoft Graph.

Creamos una Colección de Scripts para que el Groovy Script pueda ser reutilizado en varios flujos de integración.

En la vista de diseño, donde también crea flujos de integración, puede crear una colección de scripts:

Seleccione la opción «Guión Groovy»:

Introduzca un nombre para Groovy Script.

En el lado derecho aparece un Groovy Script pregenerado que sobreescribimos en el siguiente paso.

Introduce en el Groovy Script Editor el siguiente código:

/** This script fetches an access token from the OAuth2 Authorization Code credential whose name is povided in the property "OAUTH2_AUTHORIZATION_CODE_CRED".
 * sets the access token as Bearer token in the the haeder "Authorization",
 * and creates a body in JSON format (as described in https://learn.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http)
 * which can be sent to the Microsoft Graph API "https://graph.microsoft.com/v1.0/me/sendMail" via the HTTP receiver adapter.
 * 
 * The incomming message body is used as mail body and it is assumed the the incmming message body has a charset encoding of UTF-8.
 * 
 * The script is parametrized by the following properties:
 * - "OAUTH2_AUTHORIZATION_CODE_CRED": name of the OAuth2 Authorization Code credential created before (in our example: "SEND_MAIL_VIA_GRAPH_API")
 * - "MAIL_SAVE_TO_SENT_ITEMS": indicator whether to save the sent mail into the "Send Items" folder of the mail account
 * - "MAIL_RECIPIENT": e-mail address of the mail recipient
 * - "MAIL_CC_RECIPIENT": optional e-mail address of the cc recipient
 * - "MAIL_SUBJECT": subject of the mail
 * - "MAIL_ATTACHMENT": optional property containing the base 64 encoded mail attachment
 * - "MAIL_ATTACHMENT_CONTENT_TYPE": content type of the mail attachment (example: "text/plain"), only necessary if MAIL_ATTACHMENT is provided
 * - "MAIL_ATTACHMENT_NAME": name of the mail attachment, only necessary if MAIL_ATTACHMENT is provided
 */

/* Refer the link below to learn more about the use cases of script.
https://help.sap.com/viewer/368c481cd6954bdfa5d0435479fd4eaf/Cloud/en-US/148851bf8192412cba1f9d2c17f4bd25.html

If you want to know more about the SCRIPT APIs, refer the link below
https://help.sap.com/doc/a56f52e1a58e4e2bac7f7adbf45b2e26/Cloud/en-US/index.html */
import com.sap.gateway.ip.core.customdev.util.Message
import java.util.HashMap
import com.sap.gateway.ip.core.customdev.util.Message
import com.sap.it.api.securestore.SecureStoreService
import com.sap.it.api.securestore.AccessTokenAndUser
import com.sap.it.api.securestore.exception.SecureStoreException
import com.sap.it.api.ITApiFactory
import java.nio.charset.StandardCharsets
import groovy.json.JsonOutput
import java.util.Base64
import java.util.LinkedHashMap

def Message processData(Message message) {
     def properties = message.getProperties();
     
    SecureStoreService secureStoreService = ITApiFactory.getService(SecureStoreService.class, null);
    // fetch the name of the OAuth2 Authorization Code credential from the property "OAUTH2_AUTHORIZATION_CODE_CRED"
    String  oauth2AuthorizationCodeCred = properties.get("OAUTH2_AUTHORIZATION_CODE_CRED");
    if (oauth2AuthorizationCodeCred == null || oauth2AuthorizationCodeCred.isEmpty()){
        throw new IllegalStateException("Property OAUTH2_AUTHORIZATION_CODE_CRED is not specified")
    }
    // fetch access token 
    AccessTokenAndUser accessTokenAndUser = secureStoreService.getAccesTokenForOauth2AuthorizationCodeCredential(oauth2AuthorizationCodeCred);
    String token = accessTokenAndUser.getAccessToken();
    
    // set the Authorization header with the access token   
    message.setHeader("Authorization", "Bearer "+token);
    message.setHeader("Content-Type","application/json");
    
    MailMessage mailMessage = new MailMessage()
     String  mailSubject = properties.get("MAIL_SUBJECT");
    if (mailSubject == null || mailSubject.isEmpty()){
        throw new IllegalStateException("Property MAIL_SUBJECT is not specified")
    }
    mailMessage.subject = mailSubject
    
    // We assume here that the mail content is provided in the message body as byte array with UTF8 encoding
    // and that the content type is provided in the property MAIL_BODY_CONTENT_TYPE
    // 	Possible values vor the content type are  "text" and "html".
    String  contentType = properties.get("MAIL_CONTENT_TYPE");
    if (contentType == null || contentType.isEmpty()){
        throw new IllegalStateException("Property MAIL_CONTENT_TYPE is not specified")
    }
    byte[] messageBody =  message.getBody(byte[].class)
    if (messageBody == null){
         throw new IllegalStateException("Message body is null")
    }
    MailBody mailBody = new MailBody()
    mailBody.contentType = contentType
    mailBody.content = new String(messageBody,StandardCharsets.UTF_8) // we assume here that the message body is encoded in UTF8
    
    mailMessage.body = mailBody
    
    String  mailRecipient = properties.get("MAIL_RECIPIENT");
    if (mailRecipient == null || mailRecipient.isEmpty()){
        throw new IllegalStateException("Property MAIL_RECIPIENT is not specified")
    }    
    EmailAddress emailAddress = new EmailAddress()
    emailAddress.address = mailRecipient
    
    MailRecipient recipient = new MailRecipient()
    recipient.emailAddress = emailAddress
    
    // you can also add more than one recipient
    mailMessage.toRecipients.add(recipient)
   
      //mailCcRecipient is optional
    String  mailCcRecipient = properties.get("MAIL_CC_RECIPIENT");
    if (mailCcRecipient != null && (! mailCcRecipient.isEmpty())){
        EmailAddress ccEmailAddress = new EmailAddress()
        ccEmailAddress.address = mailCcRecipient
        
        MailRecipient ccRecipient = new MailRecipient()
        ccRecipient.emailAddress = ccEmailAddress
        
        mailMessage.ccRecipients.add(ccRecipient)
    }
    
    // attachment is optional, attachment must be base 64 encoded
    String  attachment = properties.get("MAIL_ATTACHMENT");
    if (attachment != null && (! attachment.isEmpty())){
        String  attachmentContentType = properties.get("MAIL_ATTACHMENT_CONTENT_TYPE");
        if (attachmentContentType == null || attachmentContentType.isEmpty()){
            throw new IllegalStateException("Property MAIL_ATTACHMENT_CONTENT_TYPE is not specified")
        }
        String  attachmentName = properties.get("MAIL_ATTACHMENT_NAME");
        if (attachmentName == null || attachmentName.isEmpty()){
            throw new IllegalStateException("Property MAIL_ATTACHMENT_NAME is not specified")
        } 
        Map<String,String> mailAttachment = new LinkedHashMap<>()
        mailAttachment.put("@odata.type","#microsoft.graph.fileAttachment")
        mailAttachment.put("name", attachmentName)
        mailAttachment.put("contentType", attachmentContentType)
        mailAttachment.put("contentBytes", attachment )
        // you can also add more than one attachment
        mailMessage.attachments.add(mailAttachment)
    }
    
    Mail mail = new Mail()
    mail.message = mailMessage;
    String  saveToSentItems = properties.get("MAIL_SAVE_TO_SENT_ITEMS");
    if (saveToSentItems == null || saveToSentItems.isEmpty()){
        // default value is true 
        mail.saveToSentItems = true
    } else {
        boolean saveToSentItemsBoolean = Boolean.valueOf(saveToSentItems);
        mail.saveToSentItems = saveToSentItemsBoolean
    }
   
    String jsonBody = JsonOutput.toJson(mail)
    message.setBody(jsonBody.getBytes(StandardCharsets.UTF_8));
    
    return message;
}

class MailBody{
    
    String contentType = "Text"
    String content
}

class EmailAddress{
    String address
}

class MailRecipient{
    
    EmailAddress emailAddress
    
}


class MailMessage{
    
    String subject
    MailBody body
    List<MailRecipient> toRecipients = new LinkedList<MailRecipient>()
    List<MailRecipient> ccRecipients = new LinkedList<MailRecipient>()
    List<Map<String,String>> attachments = new LinkedList<Map<String,String>>()
}

class Mail { 
    
    MailMessage message
    boolean saveToSentItems }

Groovy Script utiliza las siguientes propiedades:

  • OAUTH2_AUTHORIZATION_CODE_CRED: nombre de la credencial del Código de Autorización OAuth2 creada anteriormente (en nuestro ejemplo: “SEND_MAIL_VIA_GRAPH_API”)
  • MAIL_SAVE_TO_SENT_ITEMS: indicador de si guardar el correo enviado en la carpeta «Enviar elementos» de la cuenta de correo
  • CORREO_RECIPIENTE: dirección de correo electrónico del destinatario del correo
  • MAIL_CC_RECIPIENT: dirección de correo electrónico del destinatario de cc
  • CORREO_ASUNTO: asunto del correo
  • ARCHIVO ADJUNTO DE CORREO: propiedad opcional que contiene el archivo adjunto de correo codificado en base 64
  • MAIL_ATTACHMENT_CONTENT_TYPE: tipo de contenido del archivo adjunto de correo (ejemplo: «texto/sin formato»), solo es necesario si ARCHIVO ADJUNTO DE CORREO está provisto
  • MAIL_ATTACHMENT_NAME: nombre del archivo adjunto de correo, solo es necesario si ARCHIVO ADJUNTO DE CORREO está provisto

Groovy Script utiliza el cuerpo del mensaje como entrada para el cuerpo del correo y asume que el cuerpo del mensaje tiene una codificación de conjunto de caracteres de UTF-8.

Groovy Script solo permite un destinatario, un destinatario cc y un archivo adjunto. Si desea utilizar varios destinatarios, varios destinatarios de cc o varios archivos adjuntos, debe mejorar el Script.

Implemente la colección de scripts.

Creamos un flujo de integración con un paso de guión que usa la credencial del código de autorización OAuth2 creado y un adaptador de receptor HTTP que llama a Microsoft Graph API. La siguiente captura de pantalla muestra el flujo de integración que queremos construir:

Configuración del adaptador de remitente HTTPS

Configuración del Modificador de Contenido “Configurar Correo”

El paso del modificador de contenido «Configurar correo» contiene las propiedades de intercambio para el paso Groovy Script:

Las propiedades MAIL_ATTACHMENT_…, MAIL_CC_RECIPIENT y MAIL_SAVE_TO_SEND_ITEMS son opcionales. Si MAIL_SAVE_TO_SEND_ITEMS no está configurado, se utiliza la configuración predeterminada «verdadero». Vea el Groovy Script arriba.

Groovy Script Step «Preparar correo»

En el paso «Preparar correo» de Groovy Script, hacemos referencia al Groovy Script de la colección de scripts que creamos antes.

Primero, crea una referencia a la colección de scripts:

Luego puede hacer referencia al Script de la colección en el paso Groovy Script:

Paso de solicitud de respuesta «Llamar a Microsoft Graph»

Creamos una “Solicitud de respuesta” con nombre “Llamar a Microsoft Graph” a la que conectamos un adaptador de receptor HTTP.

Adaptador de receptor HTTP de configuración

Ingrese en el campo “Dirección” “https://graph.microsoft.com/v1.0/me/sendMail“,

elija «Autenticación» «Ninguno»,

e ingrese en los encabezados de solicitud «Autorización | Tipo de contenido» (estos encabezados se establecen en Groovy Script):

Llamamos al adaptador del receptor HTTP en un paso de respuesta de solicitud porque queremos limpiar los encabezados después de la llamada a Microsoft Graph. Por lo tanto, agregamos el paso del modificador de contenido «Eliminar encabezados» después del paso «Solicitud-respuesta». Lo que es más importante, eliminamos el encabezado «Autorización» que establece el paso de guión y que contiene el token. Si no eliminamos este encabezado, el token será parte de la respuesta al remitente y el remitente podría acceder a esta información relevante para la seguridad.

Para poder llamar al extremo del flujo de integración, necesita un usuario con el rol ESBMessaging.send asignado. Asumimos aquí que está familiarizado con la configuración de la autenticación básica en su cliente HTTP (por ejemplo, Postman); no explicamos la parte de autenticación del cliente HTTP.

Después de implementar el flujo de integración, encontrará el punto final del flujo de integración en la Vista de operaciones en el mosaico «Administrar contenido de integración»:

En la vista «Administrar contenido de integración», también verá la colección de scripts implementada «SendMail».

Ahora puede realizar una solicitud HTTP POST desde su cliente HTTP a este punto final con un cuerpo de solicitud. El resultado será que se envía un correo al destinatario que especificó en el Modificador de contenido «Configurar correo». El cuerpo del correo será el cuerpo que usó en la solicitud HTTP. El asunto del correo será el asunto que especificó en la propiedad “CORREO_ASUNTO” del Modificador de Contenido “Configurar Correo”.




Caso de uso del agregador de CPI: cree mensajes separados por código de empresa único
Previo
Cómo acceder a un almacén de objetos BTP: depósito de AWS S3 desde un escritorio local
Siguiente

Madrid

Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010

México

Paseo de la Reforma 26
Colonia Juárez,  Cuauhtémoc
Ciudad de México 06600

Costa Rica

Real Cariari
Autopista General Cañas, 
San José, SJ 40104

Perú

Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073

Twitter Linkedin Instagram
Copyright 2022 | All Right Reserved.