O assunto de hoje é a 1ª parte de um artigo (dividido em 2 partes) em que vou compartilhar conhecimentos gerais sobre como enviar e-mails a partir de um SGBD Oracle e mostrarei como evitar os principais problemas que você poderá encontrar tentando realizar esta tarefa. Alguns que eu mesmo passei, outros que alguns leitores do meu blog passaram e me pediram ajuda e outros que vi em fóruns.
Para enviar e-mails a partir de um SGBD Oracle, comumente utilizamos as packages UTL_MAIL e UTL_SMTP, mas é possível utilizar também a package UTL_TCP. Todas elas foram desenvolvidas pela própria Oracle e algumas precisam de instalação adicional. A UTL_SMTP é mais antiga, existe desde o Oracle 8i e já vem instalada, por padrão no BD. A UTL_MAIL está disponível a partir do Oracle 10GR2, e nada mais é do que um wrapper que utiliza as packages UTL_SMTP e UTL_TCP. Ela foi criada para facilitar o envio de e-mails, mas infelizmente, ela possui algumas restrições.
Utilizar a package UTL_SMTP para mandar e-mail é bastante complexo e trabalhoso. É bem mais fácil e mais rápido utilizar a package UTL_MAIL, mas como eu havia dito no parágrafo acima, ela possui algumas restrições, tais como: enviar somente 1 anexo e o tamanho do anexo deve ser de no máximo 32K. Estas restrições não existem na package UTL_SMTP, que não vou explicar neste artigo. Na 2a. parte vou compartilhar uma package que usa tanto a UTL_SMTP quanto a UTL_MAIL para enviar e-mails. O código desta package poderá servir como referência para quem pretende ver como usar qualquer uma delas.
Explicarei abaixo como usar a UTL_MAIL, por ser a opção mais simples e atualmente a mais utilizada. Para utilizá-la é necessário cumprir alguns pré-requisitos:
1- Instalar a package executando os scripts: $ORACLE_HOME/rdbms/admin/utlmail.sql e $ORACLE_HOME/rdbms/admin/prvtmail.plb. A instalação deve ser efetuada por um usuário que tenha privilégios de DBA;
2- Configurar o parâmetro de sistema SMTP_OUT_SERVER, com um valor contendo o nome ou IP + porta de um servidor SMTP válido. Se você omitir o endereço da porta, será utilizada como padrão, a porta 25. É importante salientar que a máquina host do BD tenha comunicação com o servidor SMTP, e também, autorização para enviar mensagens (no software do servidor SMTP não deve existir regras que bloqueiem mensagens da máquina host do BD).
Ex.: ALTER SYSTEM SET smtp_out_server = 'smtp.empresa.com.br:25';Obs.: Para executar o comando acima é necessário ter privilégios de DBA.
3- O remetente (sender) do e-mail deve ser uma conta de e-mail que não requer autenticação para envio de mensagens.
Após cumprir os pré-requisitos acima, você já poderá utilizar a package UTL_MAIL. Segue abaixo, um bloco PL/SQL simples, que contém comentários sobre o que deve ser passado como valor em cada parâmetro, e que pode ser utilizado para enviar um e-mail sem anexo, utilizando a procedure SEND desta package:
BEGIN
UTL_MAIL.SEND
(SENDER => 'email@oracle.com', -- remetente da mensagem
RECIPIENTS => 'fbifabio@gmail.com', -- destinatário da mensagem
CC => null, -- destinatário copiado na mensagem
BCC => null, -- destinatário com cópia oculta da mensagem
SUBJECT => 'Assunto do e-mail', -- assunto da mensagem
MESSAGE => 'Mensagem do e-mail', -- mensagem do e-mail
MIME_TYPE => 'text/plain; charset=iso-8859-1' -- mime type + character set do texto da mensagem
);
END;
Como pode ser observado no bloco PL/SQL acima, é muito fácil enviar uma mensagem sem anexo usando a package UTL_MAIL, mas a coisa complica quando você tem que mandar mensagens com anexo, e fica impossível quando o anexo é maior que 32K. Um detalhe em que muitos profissionais encontram problemas e dificuldades, é a configuração dos caracteres do texto das mensagens e do texto dos anexos, que podem apresentar, em muitos casos, os chamados "caracteres desconfigurados". Para evitar estes caracteres desconfigurados é necessário passar o valor adequado para os parâmetros MIME_TYPE, que indicam o tipo de aplicação e o conjunto de caracteres que será utilizado para compor o texto da mensagem ou do anexo . Eu normalmente configuro o valor 'text/plain; charset=iso-8859-1' e isso já é suficiente para resolver os meus problemas. Se para você esta configuração apresentar caracteres desconfigurados, troque o valor iso-8859-1 por utf-8 ou us-ascii (valor padrão). Para aqueles que ainda assim tiverem problemas e precisarem de mais informações sobre mime types, sugiro a leitura do artigo http://en.wikipedia.org/wiki/MIME.
Se você tentar mandar um e-mail em um BD 11G, possivelmente você irá se deparar com erro ORA-24247: acesso à rede negado pela ACL (access control list), pois nesta versão do Oracle, para aumentar a segurança do BD, foi acrescentado um controle de acesso mais rígido às packages UTL_MAIL, UTL_SMTP e outras, em que é necessário conceder privilégios especiais ao usuários que irão executá-las. Não iremos entrar em detalhes sobre ACL neste artigo, mas para conceder estes privilégios a um usuário chamado FABIO, por exemplo, execute os blocos PL/SQL abaixo:
begin
dbms_network_acl_admin.create_acl (
acl => 'grant_acl.xml',
description => 'Permite enviar e-mail e usar outras packages',
principal => 'FABIO', -- observe que o nome do usuário deve estar sempre em UPPERCASE
is_grant => TRUE,
privilege => 'connect' -- este privilégio concedido é que permite que o usuário envie email através do servidor que será especificado no próximo bloco que chama a SP "assign_acl"
);
commit;
end; /
begin
dbms_network_acl_admin.assign_acl(
acl => 'grant_acl.xml',
host => 'hostname' -- preencha aqui o nome do host do servidor SMTP
);
commit;
end;
/
Na próxima parte deste artigo, compartilharei com vocês, uma package que eu desenvolvi para facilitar o trabalho de envio de e-mails com ou sem anexo. Essa package internamente utiliza a package UTL_MAIL para enviar mensagens sem anexo e a package UTL_SMTP para enviar mensagens com anexo. O objetivo de criá-la foi para padronizar o código de envio de e-mails na empresa em que eu trabalho e facilitar o envio de e-mails com anexos maiores que 32K, pois não é muito fácil utilizar a package UTL_SMTP para essa finalidade.Por hoje é só! Aguardem a 2a. parte!
A 2a. parte deste artigo já foi publicada AQUI
[]s
Quero treinamento de PL\SQL para SQL Server é possivel??
ResponderExcluirTchaiser, PL/SQL não existe em SQL Server. A linguagem correspondente em SQL Server chama-se Transact SQL. Infelizmente não sou especialista em SQL Server, e por isso, não ministro treinamentos neste SGBD.
Excluir[]s
Tchaiser, nesse site você irá encontrar um ótimo material para PL/SQL. Recomendo.
Excluirwww.aprendavirtual.ninehub.com
Tem as minhas vídeoaulas também que são mais caras, mas meu foco não é quantidade e sim qualidade e suporte! Todo aluno meu tem suporte que respondo em média em até 1 dia útil e qdo o aluno ainda não consegue entender por email eu acabo tirando a dúvida por telefone.
Excluir[]s
Muito boa dica Fabio, estou ansioso para a segunda parte !
ResponderExcluirUma dúvida que ficou, a pkg UTL_SMTP possibilita anexos maiores? e ou o envio de mais de um anexo?
Vinicius, obrigado pelo comentário.
ExcluirQuanto à sua resposta, sim, a UTL_SMTP possibilita anexos maiores que 32K e também possibilita enviar mais de 1 anexo. A package que eu desenvolvi e irei compartilhar na 2a. parte do artigo usará a UTL_SMTP para enviar anexos maiores que 32K, mas não contemplará múltiplos anexos, oK?
[]s
Oi Fábio, me surgiu uma dúvida, tenho o banco 11g R2 instalado no linux e estou testando o envio de email via as tuas dicas, só que não entendi direito como posso fazer para rodar os scripts utlmail.sql e prvtmail.plb, em minha instalação eles estão em /opt/oracle/product/11.2.0/db/rdbms/admin/. Como faço para rodar os mesmos, existe uma forma de eu rodar acessando via o Oracle SQL Developer, PL/SQL developer, Toad ou somente é possível via sqlplus diretamente no servidor? Outra coisa, caso eu execute estes scripts como usuário sys (SYSDBA), como poderei acessar, tipo rodar o script abaixo via um usuário comum do banco:
ResponderExcluirBEGIN
UTL_MAIL.SEND
(SENDER => 'email@oracle.com', -- remetente da mensagem
RECIPIENTS => 'fbifabio@gmail.com', -- destinatário da mensagem
CC => null, -- destinatário copiado na mensagem
BCC => null, -- destinatário com cópia oculta da mensagem
SUBJECT => 'Assunto do e-mail', -- assunto da mensagem
MESSAGE => 'Mensagem do e-mail', -- mensagem do e-mail
MIME_TYPE => 'text/plain; charset=iso-8859-1' -- mime type do texto da mensagem
);
END;
Att,
Douglas, vc precisará executar os scripts diretamente no servidor ou copiá-los para a sua máquina, aí sim vc poderá executá-los no SQL Developer ou qq outra ferramenta.
ResponderExcluirQto ao executar o código com usuário comum que não tenha privilégios de DBA ou SYSDBA, é necessário somente executar 2 passos:
1- permitir que o usuario execute a package, executando o comando abaixo logado como SYS ou usuario q tenha privilégios de DBA:
GRANT EXECUTE ON UTL_MAIL TO USUARIO;
2- atribuir os privilégios de ACL que mencionei no artigo (logado como SYS ou usuario q tbém tenha privs de DBA), ok?
[]s
Fábio, ao rodar o script abaixo como usuário sys:
ResponderExcluirbegin
dbms_network_acl_admin.create_acl (
acl => 'grant_acl',
description => 'Permite enviar e-mail e usar outras packages',
principal => 'AFBWEBP1',
is_grant => TRUE,
privilege => 'connect'
);
commit;
end;
Me é retornado o seguinte erro:
ORA-46059:Identificador ACL inválido especificado
Saberias me dizer o que pode estar acontecendo?
Tinha um erro no artigo, que eu já corrigi!
ExcluirTodo nome de ACL deve conter o sufixo .xml, portanto, substitua 'grant_acl' por 'grant_acl.xml', OK?
Ok Fábio, rodei os comandos acima sem problemas, mas ao rodar o script:
ResponderExcluirBEGIN
UTL_MAIL.SEND
(SENDER => 'email@oracle.com', -- remetente da mensagem
RECIPIENTS => 'douglascar@gmail.com', -- destinatário da mensagem
CC => null, -- destinatário copiado na mensagem
BCC => null, -- destinatário com cópia oculta da mensagem
SUBJECT => 'Assunto do e-mail', -- assunto da mensagem
MESSAGE => 'Mensagem do e-mail', -- mensagem do e-mail
MIME_TYPE => 'text/plain; charset=iso-8859-1' -- mime type do texto da mensagem
);
END;
Me foi retornado o erro de ACL:
ORA-24247: acesso à rede negado pela ACL (access control list)
Eu acho que vc errou ao executar o bloco abaixo:
Excluirbegin
dbms_network_acl_admin.assign_acl(
acl => 'grant_acl.xml',
host => 'hostname' -- preencha aqui o nome do host do servidor SMTP
);
commit;
end;
/
Substitua hostname pelo nome ou IP do host do servidor SMTP, OK? Acrescentei comentários em laranja no artigo para ficar mais fácil de entender!
[]s
Fábio, executei novamente os passos e o erro estava no passo 2, onde havia colocado errado o comando: ALTER SYSTEM SET smtp_out_server = 'smtp.empresa.com.br:25';
ResponderExcluirAcertei o mesmo e funcionou. Fiz o teste da segunda parte que é o envio do email com anexo e utilizei o seguinte script para testar o envio com anexo:
DECLARE
V_CLOB CLOB;
BEGIN
V_CLOB := 'Teste de envio de email';
PKG_ENVIA_EMAIL.SP_ENVIAR_EMAIL_COM_ANEXO (P_ASSUNTO => 'Assunto do e-mail',
P_MSG => 'Mensagem',
P_EMAIL_ORIGEM => 'oracle@oracle.com',
P_EMAIL_DESTINO => 'fbifabio@gmail.com, jack@oracle.com',
P_EMAIL_CC_DESTINO => 'ze@oracle.com, jo@oracle.com',
P_EMAIL_CCO_DESTINO => null,
P_FILENAME => 'arquivo.txt',
P_ANEXO => V_CLOB, -- variável CLOB c/ texto do arquivo
P_ATTACH_MIME => 'text/plain; charset=iso-8859-1',
P_SMTP_SERVER => 'smtp.empresa.com.br',
P_SMTP_PORT => 25);
END;
Obrigado pela ajuda Fábio.
Fábio, bom dia:
ResponderExcluirSeria legal informar (principalmente para os iniciantes como eu em BD)que em alguns casos o comando para configurar o smtp_out_server deve vir seguido do arquivo de parâmetro do servidor.
Eu não estava conseguindo e após pesquisar e inserir este complemento, o sistema foi alterado.
ALTER SYSTEM SET smtp_out_server = 'smtp.empresa.com.br:25' scope:spfile;
Abs,
ok , já está no artigo.
ExcluirBoa tarde Fabio, tenho uma dúvida que é a seguinte, como enviar varios emails na mesma execução da procedure, por exemplo que nem no outlook o separador é ";" (ponto e virgula) que ficaria assim ao executar a procedure recipients => email01@servidor.com.br;email01@servidor.com.br;. Porém o mesmo não funcionou o erro da mensagem diz que não existe este e-mail (claro tentei com outros emails este é apenas um exemplo), acredito que ele não esteja interpretando o ";" (ponto-virgula), como um separador de emails e que adicione mais de 1 e-mail para cada ";" (ponto-virgula) que encontra. Obrigado desde já.
ResponderExcluirLeandro, na package que eu disponibilizei na 2a. parte deste artigo, utilize caractere "," ao invés de ";", ok?
ExcluirBoa Tarde Fabio,
ResponderExcluirestou utilizando o comando utl_smtp para enviar um html, a imagem do html é recebida porém a acentuação não funciona, mesmo utilizando na montagem do html a tabela de acentos e caracteres do html. Tem alguma dica? obrigada
Boa tarde Sil, veja na 2a parte deste artigo o parâmetro P_ATTACH_MIME da procedure PKG_ENVIA_EMAIL.SP_ENVIAR_EMAIL_COM_ANEXO. Vc tem que passar o valor correto para ele não desconfigurar os caracteres. Dentro desta procedure vc pode ver o código que utiliza a UTL_MAIL e extrair o que vc precisa para corrigir o problema.
Excluir[]s
Oi Fabio, descompactei a package PKG_ENVIA_EMAIL para comparar com o desenvolvimento que fiz, alterar o parametro para 'text/plain; charset=iso-8859-1' fez com que recebesse o texto do html no corpo do email. Tenho utilizado: utl_smtp.write_data(mail_conn, 'Content-Type: text/html; charset="iso-8859-1"' ||utl_tcp.crlf || utl_tcp.crlf);
ResponderExcluirDesta forma recebo o email com a imagem gerada pelo html, o problema é a desconfiguração dos acentos. Onde está escrito charset= "iso-8859-1" ja testei charset = 'utf-8' mas sem êxito.
Teste outras configurações. Veja o que falo sobre mime types aqui neste artigo.
Excluir[]s
Boa Tarde Fabio,
ResponderExcluirFiz uns testes, utilizei um codigo pronto do link abaixo, mas no lugar dos acentos recebo o caracter '?' :
http://do-while-true.blogspot.com.br/2012/02/sending-utf-8-html-email-using-utlsmtp.html
Encontrei também a descrição do que está ocorrendo no link abaixo:
http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/u_smtp.htm#i1004292
Na parte que menciona: Text (VARCHAR2) data sent using WRITE_DATA is converted to US7ASCII before it is sent. If the text contains multibyte characters, each multibyte character in the text that cannot be converted to US7ASCII is replaced by a '?' character. If 8BITMIME extension is negotiated with the SMTP server using the EHLO subprogram, multibyte VARCHAR2 data can be sent by first converting the text to RAW using the UTL_RAW package, and then sending the RAW data using WRITE_RAW_DATA.
Continuo nas tentativas, caso tenha alguma dica me envie por favor.
Obrigada
Oi Fabio,
ResponderExcluirDeu certo agora!!!
Fiz o seguinte: declarei o charset como US7ASCII
e utilizei :
UTL_SMTP.WRITE_RAW_DATA(conn,
UTL_ENCODE.QUOTED_PRINTABLE_ENCODE(UTL_RAW.CAST_TO_RAW(p_message)));
Vou passar o codigo completo, para se achar interessante publicar.
Muito obrigada pela ajuda e atenção!
OK Sil, obrigado!
ExcluirOlá Fabio,
ResponderExcluirSabe me informar se existe algum script que faça a desinstalação do UTL_MAIL?
Não conheço nenhum script, mas é muito simples fazer isso. Basta apagar a package UTL_MAIL, que existe no schema SYS. CUIDADO ao mexer neste schema! Se vc apagar ou alterar algo erroneamente, vc poderá ter sérios problemas no seu BD.
Excluir[]s
Bom dia Fabio,
ResponderExcluirEstamos migrando os emails para o office 365 e em um teste simples, está sendo apresentando a mensagem ORA-29279: erro permanente de SMTP: 530 5.7.57 SMTP: Client was not authenticated to send anonymous mail during MAIL FROM.
Estou usando o UTL_MAIL e preciso usar ele, pois todas as aplicações estão amarradas nele.
Apliquei a alteração do smtp_out_server ALTER SYSTEM SET smtp_out_server = 'smtp.office365.com:25';
Fiz testes tanto com o nome ou o ip e mesmo assim apresenta falha.
Existe algo diferente para o Office 365?
Abraço.
Bom dia Cristiano,
ExcluirA conta que você está utilizando para enviar mensagens tem que ter uma configuração especial para enviar mensagens sem autenticação. Verifique como fazer isso no seu gerenciador de e-mail.
[]s