X for Dummies

Como enviar e-mail SSL usando AX 2009

Publicado em AX2009, Tutoriais, X++, 10/04/2013, por Edvandro Santos

2


Segurança na internet é um assunto recorrente, importante e complicado. Empresas e profissionais procuram sempre a melhor forma de manterem-se seguros dentro da grande rede de informações. E com o e-mail não é diferente. Principalmente quem usa serviços com gMail, Microsoft On-line Services, etc.

Por isso hoje eu vou mostrar como enviar e-mail pelo AX via contas cuja função SMTP usa SSL.

Por padrão, para o envio de e-mail com a função de SMTP, o AX é projetado para se comunicar com o servidor de e-mail dentro do mesmo domínio / LAN. O principal problema é que a classe SysMailer, utilizada para o envio por SMTP, requer que o servidor de e-mail permita a retransmissão.

A solução, então, é utilizar C# para realizar o procedimento. Acompanhe os passos abaixo:

1. Novo EDT

a. Acesse AOT > Data Dictionary > Extended Data Types;

b. Clique com o botão menu de contexto sobre o nó e selecione Novo >  Enum;

c. Configure o Base Enum com as propriedades abaixo:

  • Name: SysEmailSSL
  • Label: Habilitar SSL?
  • HelpText: Habilita o uso de SSL para envio de e-mail
  • Extends: NoYesId
  • EnumType: NoYes

2. Customização da tabela SysEmailParameters

a. Acesse AOT > Data Dictionary > Tables > SysEmailParameters > Fields;

b. Clique com o botão menu de contexto sobre o nó e selecione Novo > Enum;

c. Configure o campo com as propriedades abaixo:

  • Type: Enum
  • Name: SSL
  • Mandatory: No
  • ExtendedDataType: SysEmailSSL
  • EnumType: NoYes

d. Sincronize e compile a tabela

3. Customização do form SysEmailParameters

a. Acesse AOT > Forms > SysEmailParameters > Designs > Design > Tab:Tab > TabPage:General > Group:SMTP;

b. Clique bom o botão menu de contexto sobre o nó e selecione Novo Control > Checkbox;

c. Configure o campo com as propriedades abaixo:

  • Name: SysEmailParameters_SSL
  • DataSource: SysEmailParameters
  • DataField: SSL

4. Adicionar referência ao System.Net na AOT

a. Acesse AOT > References;

b. Clique com o botão menu de contexto sobre o nó e selecione Adicionar referência;

c. Procure pela referência System.Net e clique em Selecionar;

d. Clique em OK;

5. Criar método para envio do e-mail usando SSL

a. Acesse AOT > Class > SysEmailDistributor;

b. Clique com o botão menu de contexto sobre o nó e selecione Novo method;

c. No novo método criado, coloque a função abaixo:

void processEmailsFramework(SysEmailProcessorId _emailProcessorId)
{
    SysOutgoingEmailTable outgoingEmailTable; // Tabela que contém os e-mails a serem enviados
    SysOutgoingEmailData outgoingEmailData; // Tabela que contém os arquivos a serem
                                            // incorporados ao e-mail
    SysEmailTable emailTable; // Tabela que contém os modelos de e-mail configurados no sistema:
                              // Básico > Configuração > Modelos de e-mail
    SysEmailMessageTable emailMessage; // Tabela que contém o corpo do e-mail criado no modelo

    utcDateTime nextRetryDateTime;

    SysEmailRetryNum retryNum;

    BinData binData;

    FileIOPermission fileIOPermission;
    InteropPermission permission;

    str relayServer;
    int portNumber;
    str userName;
    str password;
    boolean useNTLM;
    boolean useSSL;

    str filePathName;
    str tempPath;

    //Classes System.Net
    System.Net.Mail.SmtpClient                  smtpMail;
    System.Net.ICredentialsByHost               networkCredential;
    System.Net.Mail.MailAddress                 fromAddress;
    System.Net.Mail.MailAddress                 recipient;
    System.Net.Mail.MailMessage                 mailMessage;
    System.Net.Mail.AttachmentCollection        attachementCollection;
    System.Net.Mail.Attachment                  attachment;
    System.Net.Mail.LinkedResourceCollection    linkedResourceCollection;
    System.Net.Mail.LinkedResource              linkedResource;

    SysEmailParameters parameters = SysEmailParameters::find();

    if (parameters.SMTPRelayServerName)
        relayServer =   parameters.SMTPRelayServerName;
    else
        relayServer = parameters.SMTPServerIPAddress;

    portNumber =  parameters.SMTPPortNumber;
    userName =  parameters.SMTPUserName;
    password = SysEmailParameters::password();
    useNTLM = parameters.NTLM;
    useSSL = parameters.SSL;

    fileIOPermission = new FileIOPermission('','r');
    fileIOPermission.assert();

    //BP Deviation Documented
    tempPath = WinApiServer::getTempPath();

    CodeAccessPermission::revertAssert();

    // Obtem e-mails com status "Executando" para seu processamento.
    // Esse processo não bloqueia o acesso aos registros da tabela caso haja algum processo em paralelo
    while select optimisticlock outgoingEmailTable
        index hint StatusIdx
        where outgoingEmailTable.Status == SysEmailStatus::Executing &&
              outgoingEmailTable.ProcessorID == _emailProcessorId
    {
        if ( !outgoingEmailTable.Sender || !outgoingEmailTable.Recipient)
        {
            SysOutgoingEmailTable::markEmailAs(outgoingEmailTable.EmailItemId,SysEmailStatus::Failed,true);
        }
        else
        {
            try
            {
                //Configuração do SMTP
                permission = new InteropPermission(InteropKind::ClrInterop);
                permission.assert();
                //BP Deviation Documented
                smtpMail = new System.Net.Mail.SmtpClient(relayServer, portNumber);
                smtpMail.set_EnableSsl(useSSL);

                if (useNTLM)
                    smtpMail.set_UseDefaultCredentials(useNTLM);
                else
                {
                    //BP Deviation Documented
                    networkCredential = new System.Net.NetworkCredential(userName, password);
                    smtpMail.set_Credentials(networkCredential);
                }

                //Obtendo o template do E-mail (Básico > Configuração > Modelos de E-mail)
                emailTable = SysEmailTable::find(outgoingEmailTable.TemplateId);
                emailMessage = SysEmailMessageTable::find(outgoingEmailTable.TemplateId, emailTable.DefaultLanguage);

                //BP Deviation Documented
                fromAddress = new System.Net.Mail.MailAddress(outgoingEmailTable.Sender,outgoingEmailTable.SenderName);
                //BP Deviation Documented
                recipient = new System.Net.Mail.MailAddress(outgoingEmailTable.Recipient);
                //BP Deviation Documented
                mailMessage = new System.Net.Mail.MailMessage(fromAddress, recipient);

                switch (outgoingEmailTable.Priority)
                {
                    case eMailPriority::High:
                         mailMessage.set_Priority(System.Net.Mail.MailPriority::High);
                    break;
                    case eMailPriority::Low:
                         mailMessage.set_Priority(System.Net.Mail.MailPriority::Low);
                    break;
                    default:
                         mailMessage.set_Priority(System.Net.Mail.MailPriority::Normal);
                    break;
                }

                mailMessage.set_BodyEncoding(System.Text.Encoding::get_UTF8());
                mailMessage.set_Subject(outgoingEmailTable.Subject);
                mailMessage.set_Body(outgoingEmailTable.Message);

                if (emailMessage.LayoutType == SysEmailLayoutType::StaticLayout)
                    mailMessage.set_IsBodyHtml(true);

               //Incorporando arquivos à mensagem a ser enviada (Fotos, vídeos, mensagens, documentos, etc)
                while select outgoingEmailData
                    index hint EmailDataIdx
                    where outgoingEmailData.EmailItemId == outgoingEmailTable.EmailItemId
                {
                    if (SysEmailDistributor::validateFileName(outgoingEmailData.FileName))
                    {
                        binData = new BinData();

                        binData.setData(outgoingEmailData.Data);

                        if (outgoingEmailData.EmailDataType == SysEmailDataType::Embedded)
                            // as imagens incorporadas no e-mail serão renomeadas para manter sua identificação única
                            filePathName = tempPath + int642str(outgoingEmailData.EmailItemId) + '_' + int2str(outgoingEmailData.DataId);
                        else
                            filePathName = tempPath + outgoingEmailData.FileName;

                        if (outgoingEmailData.FileExtension)
                            filePathName = filePathName  + outgoingEmailData.FileExtension;

                        fileIOPermission = new FileIOPermission(filePathName,'w');
                        fileIOPermission.assert();

                        //BP Deviation Documented
                        binData.saveFile(filePathName);

                        CodeAccessPermission::revertAssert();

                        if (outgoingEmailData.EmailDataType == SysEmailDataType::Embedded)
                        {
                            //BP Deviation Documented
                            linkedResource = new System.Net.Mail.LinkedResource(filePathName);
                            linkedResource.set_ContentId(int2str(outgoingEmailData.DataId));
                            linkedResourceCollection.Add(linkedResource);
                        }
                        else
                        {
                            //BP Deviation Documented
                            attachment = new System.Net.Mail.Attachment(filePathName);
                            attachementCollection.Add(attachment);
                        }

                        fileIOPermission = new FileIOPermission(filePathName,'w');
                        fileIOPermission.assert();

                        //BP Deviation Documented
                        WinApiServer::deleteFile(filePathName);

                        CodeAccessPermission::revertAssert();
                    }

                }

                smtpMail.Send(mailMessage);

                CodeAccessPermission::revertAssert();

                SysOutgoingEmailTable::markEmailAs(outgoingEmailTable.EmailItemId,SysEmailStatus::Sent);
            }
            catch (Exception::Error)
            {
                infolog.clear(0);

                if ( outgoingEmailTable.WithRetries == true)
                {
                    if (outgoingEmailTable.Status == SysEmailStatus::Unsent)
                        retryNum = 1;
                    else
                        retryNum = outgoingEmailTable.RetryNum + 1;

                    nextRetryDateTime = SysEmailRetrySchedule::nextRetryDateAndTime(retryNum);

                    if (nextRetryDateTime != utcDateTimeNull())
                    {
                        SysOutgoingEmailTable::scheduleSendRetry(outgoingEmailTable.EmailItemId,nextRetryDateTime);
                    }
                    else
                    {
                        SysOutgoingEmailTable::markEmailAs(outgoingEmailTable.EmailItemId,SysEmailStatus::Failed,true);
                    }
                }
                else
                   SysOutgoingEmailTable::markEmailAs(outgoingEmailTable.EmailItemId,SysEmailStatus::Failed);

            }
        }
    }
}

d. Altere o método run para executar o novo método criado:

De:
    this.processEmails(thisProcessorId);

Para:
    this.processEmailsFramework(thisProcessorId);

e. Acesse Administração > Configuração > Parâmetros de email e marque a opção Habilitar SSL? para testar a funcionalidade usando o método ::sendMail da tabela SysEmailTable:

static void TesteEnvioEmailSSL(Args _args)
{
    SysEmailId emailId; // Id de um modelo de e-mail configurado no sistema
    LanguageId languageId;
    ;

    emailId    = (select firstfast EmailId from sysEmailTable).EmailId;
    languageId = CompanyInfo::find().LanguageId;

    // Enviando o e-mail:
   SysEmailTable::sendMail(emailId, languageId, "blog@axfordummies.com");
}

6. Considerações

a. Certifique-se de que a porta SMTP não esteja bloqueada. A porta SMTP padrão é 25 ou 587 (SSL);

b. Certifique-se de que a Transport Layer Security (TLS) / Security Socket Layer (SSL) está habilitado em seu cliente SMTP. Na maioria dos aplicativos, isto fica em “Meu servidor de correio de saída (SMTP) requer uma conexão criptografada (SSL)”. Marque essa opção.

[ ] ‘s


  • Amith Prasanna

    Thankyou for your great solution.I tried with same modification with Ax2012 but it wasn’t work.appreciate you can guide or do new article for same thing for Ax2012.

    Thanks !

    • http://www.axfordummies.com/ AX for dummies

      Hi Amith, by standard AX 2012 has already it implemented with the exception of the piece of code:

      smtpMail.set_EnableSsl(useSSL);

      Please try to replace the SysEmailBatch.run() method adding this code.

      Best regards

Autor

Edvandro Santos

Desenvolvedor de software desde 2005, é certificado em JAVA e MCP em Microsoft Dynamics AX 2009. Com projetos desenvolvidos para IBOPE, IG, NOKIA, Huawei e Siemens, nerd assumido e fã de rock ‘n roll, quadrinhos, sci-f e blues.