Integrando Exchange Online Services con DotNetNuke

Una de las características que nos encontramos cuando tenemos alojado DotNetNuke en Azure es que no disponemos de un servidor SMTP para el envío de los correos de notificación que usa el gestor de contenidos.

La solución pasa por una de las siguientes alternativas muy bien expuestas en el post de Christian Weyer:

  • Usar un proveedor externo que pueda ayudar en el envío de correos
  • Conectar a tu servidor SMTP On-Premises
  • Usar APIs/Servicios expuestos por terceros para el envío

Bajo el último enfoque entran los servicios expuestos por Exchange Online, servicio que a través del pago de 5$ al mes/usuario podemos contar con la capacidad de un servidor de Exchange alojado en la nube –recordad que podéis probar la suite BPOS durante un periodo de 30 días sin compromiso.

Para usar los servicios de Exchange Online desde DNN realizaremos una serie de modificaciones en el portal para usar los servicios web que nos ofrece. El WSDL de estos servicios está accesible según la región donde se hayan solicitado los mismos:

Asia y Pacífico (APAC) https://red003.mail.apac.microsoftonline.com/ews/Services.wsdl
Europa (EMEA) https://red002.mail.emea.microsoftonline.com/ews/Services.wsdl
Norte América (NA) https://red001.mail.microsoftonline.com/ews/Services.wsdl

El WSDL nos ofrece una completa información acerca de los webmethods disponibles para operar remotamente con Exchange, aunque para simplificar su uso utilizaremos la EWS Managed API 1.1, que podéis descargar desde este enlace.

WSDL

En los pasos siguientes vamos a realizar unas pequeñas modificaciones en nuestro portal DNN para usar estos servicios web de Exchange Online.

Modificar el DNN core para conectar con BPOS

Como lo que deseamos es ampliar la funcionalidad actual del DNN para soportar BPOS y permitir seguir seleccionando un servidor SMTP, comencemos por modificar las opciones de configuración del host –para realizar estas modificaciones será necesario disponer del código fuente de DotNetNuke Community, que pueden descargar la última versión desde este enlace.

1. Añadir el enumerado MailServerType en el proyecto DotNetNuke.Library, en el archivo LibraryServicesMailMailServerType.vb (crear el archivo):

Namespace DotNetNuke.Services.Mail
    Public Enum MailServerType
        SMTP
        BPOS
    End Enum
End Namespace

2. Añadimos en la clase DotNetNuke.Entities.Host.Host la propiedad MailServerType:

''' <summary>
''' Gets the MailServerType (SMTP or BPOS)
''' </summary>
Public Shared ReadOnly Property MailServerType As DotNetNuke.Services.Mail.MailServerType
   Get
      Return CType(HostController.Instance.GetInteger("MailServerType"), DotNetNuke.Services.Mail.MailServerType)
   End Get
End Property

3. Agregamos una referencia a la EWS Managed API. La instalación no la coloca en la GAC para prevenir problemas con otras posibles instalaciones futuras –ese es el motivo que pone en la documentación-, así que tenemos que buscar la librería que por defecto se instala en la ruta: C:Program FilesMicrosoftExchangeWeb Services1.1Microsoft.Exchange.WebServices.dll. Aseguraos de poner el ensamblado como “Copia local=true” para que se copie automáticamente el ensamblado en el “bin” de DotNetNuke al generar el core.

AddReference

Assembly

4. Importar el espacio de nombres Microsoft.Exchange.WebServices.Data a través de las propiedades del proyecto

5. Añadir un discriminador en la rutuna SendMail de la clase “Mail” para detectar si el envío es a través de Exchange Online:

' Send using BPOS instead of SMTP
If Host.MailServerType = MailServerType.BPOS AndAlso SMTPServer = Host.SMTPServer Then
   Return SendMailBPOS(MailFrom, MailTo, Cc, Bcc, ReplyTo, Priority, Subject, BodyFormat, BodyEncoding, Body, Attachments, SMTPServer, SMTPUsername, SMTPPassword)
End If

6. Agregar la rutina del envío de mensajes usando la API de Exchange:

        Public Shared Function SendMailBPOS(ByVal MailFrom As String, ByVal MailTo As String, _
            ByVal Cc As String, ByVal Bcc As String, ByVal ReplyTo As String, _
            ByVal Priority As MailPriority, ByVal Subject As String, _
            ByVal BodyFormat As MailFormat, ByVal BodyEncoding As System.Text.Encoding, ByVal Body As String, _
            ByVal Attachments As List(Of Attachment), ByVal WebServiceURL As String, _
            ByVal Username As String, ByVal Password As String) As String

            SendMailBPOS = ""
            Try
                Dim service As New ExchangeService(ExchangeVersion.Exchange2007_SP1)
                service.Url = New Uri(WebServiceURL)
                service.Credentials = New System.Net.NetworkCredential(Username, Password)

                Dim objMail As EmailMessage = New EmailMessage(service)
                objMail.From = New EmailAddress(MailFrom)
                If MailTo <> "" Then
                    objMail.ToRecipients.Add(MailTo)
                End If
                If Cc <> "" Then
                    objMail.CcRecipients.Add(Cc)
                End If
                If Bcc <> "" Then
                    objMail.BccRecipients.Add(Bcc)
                End If

                If ReplyTo <> String.Empty Then objMail.ReplyTo.Add(New EmailAddress(ReplyTo))
                Select Case Priority
                    Case MailPriority.High : objMail.Importance = Importance.High
                    Case MailPriority.Low : objMail.Importance = Importance.Low
                    Case Else : objMail.Importance = Importance.Normal
                End Select
                objMail.Subject = HtmlUtils.StripWhiteSpace(Subject, True)
                objMail.Body = New MessageBody(CType(IIf(BodyFormat = MailFormat.Html, BodyType.HTML, BodyType.Text), BodyType), Body)

If Attachments.Count > 0 Then
objMail.Save()
' Add Attachments, converting from MailAttachments to Exchange Attachements
For Each myAtt As Attachment In Attachments
Dim mFilename As String = IO.Path.GetTempFileName()
Using fStream As New IO.FileStream(mFilename, IO.FileMode.OpenOrCreate)
Dim bArray As Byte()
ReDim bArray(CInt(myAtt.ContentStream.Length))
myAtt.ContentStream.Read(bArray, 0, CInt(myAtt.ContentStream.Length))
fStream.Write(bArray, 0, bArray.Length)
fStream.Close()
End Using
objMail.Attachments.AddFileAttachment(mFilename).Name = myAtt.Name
' It's is necessary to call .Save() in order to upload the attachment to the server
objMail.Save()
Next
End If
' send the message
objMail.SendAndSaveCopy()
Catch objException As Exception
' mail configuration problem
If Not IsNothing(objException.InnerException) Then
SendMailBPOS = String.Concat(objException.Message, ControlChars.CrLf, objException.InnerException.Message)
LogException(objException.InnerException)
Else
SendMailBPOS = objException.Message
LogException(objException)
End If
End Try

End Function

 

Añadir posibilidad de configuración

Ahora toca modificar el interfaz de usuario para agregar soporte de configuración a los superusuarios del portal. Para ello, realizamos los pasos siguientes.

1. Abrir el archivo ~DesktopModulesAdminHostSettingshostsettings.ascx y buscamos en el marcado la tabla “tblSMTP”

2. Modificamos el marcado para agregar la posibilidad de indicar el tipo de servidor. También modificamos las etiquetas “tr” correspondientes a la autenticación y SSL para poder mostrarlas y ocultarlas desde el código de servidor.

    <tr>
        <td class="SubHead" style="width: 250px">
            <dnn:Label ID="plMailServerType" Text="Server type:" ControlName="cboMailServerType" runat="server" /> 
        </td>
        <td align="left">
            <asp:DropDownList ID="cboMailServerType" runat="server" AutoPostBack="true">
                <asp:ListItem Value="SMTP" resourceKey="MailServerTypeSMTP">Servidor SMTP</asp:ListItem>
                <asp:ListItem Value="BPOS"  resourceKey="MailServerTypeBPOS">Exchange Online</asp:ListItem>
            </asp:DropDownList>
        </td>
    </tr>

3. Agregamos las entradas correspondientes en los archivos .resx de recursos en la subcarpeta App_LocalResources

Resources

4. Modificamos la rutina ShowHideSMTPCredentials() y agregamos código en el evento de selección de la lista para mostrar/ocultar parámetros según esté seleccionado el tipo de servidor.

        Private Sub ShowHideSMTPCredentials()
            If optSMTPAuthentication.SelectedValue = "1" OrElse cboMailServerType.SelectedValue = "BPOS" Then
                trSMTPPassword.Visible = True
                trSMTPUserName.Visible = True
            Else
                trSMTPPassword.Visible = False
                trSMTPUserName.Visible = False
            End If
            rowSMTPAthentication.Visible = cboMailServerType.SelectedValue = "SMTP"
            rowSMTPEnableSSL.Visible = rowSMTPAthentication.Visible
        End Sub

        ''' <summary>
        ''' Fires when the Mail server type dropdownlist changes
        ''' </summary>
        Protected Sub cboMailServerType_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboMailServerType.SelectedIndexChanged
            Try
                ShowHideSMTPCredentials()
            Catch ex As Exception
                ProcessModuleLoadException(Me, ex)
            End Try
        End Sub

5. Modificamos la rutina BindData() para volcar la propiedad configurada en el dropdown

'...
cboMailServerType.SelectedValue = Entities.Host.Host.MailServerType.ToString()
ShowHideSMTPCredentials()
'...

6. Modificamos el evento cmdUpdate_Click para guardar el dato:

 HostController.Instance.Update("MailServerType", [Enum].Parse(GetType(MailServerType), cboMailServerType.SelectedValue), False)

7. Con esto podemos configurar tanto el servidor SMTP como el servidor BPOS según nos convenga:

SMTPConfig

BPOSConfig

Al pulsar sobre el enlace “Probar” que trae incorporado DNN, realiza un envío de mensaje de prueba, que como podemos observar procesa correctamente nuestro Exchange Online.

EnvioCorrecto

Conclusión

En este artículo hemos visto la posibilidad de realizar envíos de correos desde DNN a través de Exchange Online. Para ello hemos utilizado la EWS Managed API 1.1, que facilita el manejo de los servicios web expuestos por Exchange.

Si en este ejemplo lo que hemos visto es cómo realizar los envíos a través de estos servicios, los servicios que ofrece la API son numerosos pudiéndose realizar casi cualquier cosa.

¿Cuándo comenzaremos a ver módulos desarrollados para explotar las características de Exchange desde nuestro portal DNN? Voy a ver si veo alguno por SnowCovered Sonrisa

Espero que os haya servidor de ayuda.

Un saludo y happy coding!

davidjrh

David Rodriguez, is a happy Spanish guy living and working in Tenerife (Canary Islands, Spain) where he was born. He is one of the lucky ones who has the opportunity to work with cutting edge technologies at Intelequia as CTO. He has more than 20 years development background mostly based on Microsoft technologies, designing and architecting highly scalable systems like reservation systems for airlines companies. He has been working with Microsoft Azure since it was on CTP, migrating on-premise systems to the cloud, co-founding the .NET User Group TenerifeDev as well as the CSV company Intelequia Software Solutions. He is also the author of different DNN-Azure open source projects available on GitHub such as caching providers, analytics and Azure Active Directory.

Una respuesta a “Integrando Exchange Online Services con DotNetNuke”

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *