19 de maio de 2011

Enviando emails com Delphi - Parte III

Vida de programador é difícil... No início de 2010, o Google fez uma alteração no sistema online de email deles, o GMail, para substituir o método de segurança SSL então vigente no serviço pela sua versão mais nova, chamada TLS.

Por causa dessa modificação simples, muitos programas que antes conseguiam enviar email tranquilamente através do GMail falharam. Para piorar, a versão 9 do Indy não implementa nativamente o tratamento do TLS - isso só aconteceu a partir da versão 10. Ou seja, programas Delphi ou C++ Builder construídos com o Indy 9 não tinham uma solução fácil à mão para essa questão.

Na versão 10 do Indy, a solução é extremamente simples : basta configurar a propriedade UseTLS da instância de IdSMTP e manter as demais configurações:
IdSMTP1.UseTLS := utUseExplicitTLS;

Manter as demais configurações significa que o servidor deve continuar sendo smtp.gmail.com, a porta 587, com autenticação de usuário e senha. Também é obrigatório atribuir um handler para tratar a comunicação SSL/TLS. Para mais informações sobre isso e outros aspectos das configurações básicas, veja este post.

Embora não seja um processo tão direto, é possível trabalhar com TLS em Indy 9. Basicamente, é preciso enviar ao servidor de email um comando STARTTLS logo após o SMTP ter se conectado. O trecho abaixo é um código genérico que testa configurações internas para determinar se a conexão é segura. Em caso positivo, um handler é destacado para fazer o tratamento da conexão. Neste ponto, o SMTP já foi preparado com as configurações básicas necessárias.
if (TipoSeguranca = SEGURANCA_SSL) Or (TipoSeguranca = SEGURANCA_TLS) then
begin
IdSMTP.IOHandler := IdSSLIOHandlerSocket;
if (TipoSeguranca = SEGURANCA_TLS) then
begin
IdSSLIOHandlerSocket.SSLOptions.Method := sslvTLSv1;
IdSSLIOHandlerSocket.PassThrough := true;
end;
end;

{ Tenta conectar no servidor com 1 minuto de timeout }
IdSMTP.Connect (60000);

{ Emula o comportamento do TLS }
if (TipoSeguranca = SEGURANCA_TLS) then
begin
IdSMTP.SendCmd('STARTTLS', 220);
IdSSLIOHandlerSocket.PassThrough := false;
end;

if (Autentica And (not IdSMTP.Authenticate () ) then
Raise Exception.Create ('Falha na autenticação do usuário');

Ao detectar que a conexão segura exige TLS, alguns ajustes precisam ser feitos. Primeiro, mudo o método de segurança do handler para que adote o padrão para TLS. Depois, instruo o handler a codificar os comandos trocados entre ele e o servidor. Só então, podemos estabelecer a conexão.

Uma vez que a conexão está estabelecida, enviamos ao servidor o comando STARTTLS para ativar a comunicação segura na mesma porta. Por causa disso, o PassThrough que forçamos antes da conexão já pode ser desligado.

Autenticar manualmente o usuário e a senha é um preciosismo pois o método Send para envio da mensagem o fará por nós. Aqui no exemplo foi feita a autenticação explícita pra mostrar que é possível interceptar um erro de usuário/senha inválido antes de se tentar enviar a mensagem.

Agora, é só preparar uma instância do idMessage com os dados da mensagem (destinatários, assunto, corpo da mensagem, etc.) e enviá-la com o SMTP.

As considerações tecidas neste post também são válidas para quem usa o Hotmail como serviço para envio de email em suas aplicações. Há apenas duas diferenças importantes : o servidor de email, claro, é outro (smtp.live.com); também a forma de se especificar o usuário do serviço difere. No GMail, deve ser usado como nome do usuário somente o texto que vem antes do arroba (@) do endereço de email, enquanto no Hotmail o nome do usuário é o endereço completo.

Mais Informações
Enviando emails com Delphi - Parte I e Parte II, STARTTLS

9 de maio de 2011

Enviando emails com Delphi - Parte II

Há alguns dias, escrevi um post sobre o envio de emails com Delphi, mostrando a configuração básica dos componentes Indy para SMTP e também as funções que devem ser chamadas para completar o processo. No exemplo, a mensagem incluída no email era um texto simples, sem qualquer tipo de formatação.

No começo, os programas leitores de email só conseguiam trabalhar com mensagens assim, onde apenas texto era trocado. É um comportamento básico mas que ainda tem sua utilidade, principalmente quando há questões de segurança envolvidas. Com a evolução da internet, entretanto, praticamente todos os leitores de email conseguem exibir mensagens com formatação rica. Usando HTML podemos compor emails com layouts complexos, usando cores e tipos de fontes diferentes, além da inclusão de imagens, links, tabelas, animações, entre outros. Uma grande vantagem desse formato é que ele já é utilizado para construir os sites da internet. Ou seja, HMTL é uma ferramenta bastante conhecida e amplamente suportada.

Do ponto de vista do envio de email, o que há de diferente em relação ao que foi apresentado no outro post ? Basicamente, apenas dois detalhes. O primeiro é uma propriedade da mensagem que determina o tipo de conteúdo que a mensagem está trafegando. Essa característica é chamada MIME (Multipurpose Internet Mail Extensions, ou Extensões Multipropósito para Correio na Internet). O padrão para essa propriedade no corpo de um email é o valor text/plain, que significa que a mensagem é composta por um texto simples. Como queremos montá-la como um HTML, temos que avisá-la disso:
IdMessage1.ContentType := 'text/html';
IdMessage1.CharSet := 'ISO-8859-1';

Veja que eu também modifiquei o charset da mensagem. Esta propriedade indica qual é o conjunto de caracteres que a mensagem está usando. Como o português usa acentuação, é preferível trocar o padrão americano pelo conjunto latino ('ISO-8859-1').

O outro detalhe é que o corpo da mensagem agora tem que respeitar o MIME configurado. Quero dizer com isso que teremos que montar um HTML para a mensagem:
IdMessage1.Body.Text := '<html><head>' +
'<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">' +
'</head><body>' +
'<p>Essa mensagem é um <b>Teste</b> de email HTML.</p>' +
'</body></html>';

Embora pareça redundante, é importante informar de novo no cabeçalho do HTML quem é o MIME e o charset. Os leitores de email utilizam as informações desse cabeçalho para renderizar a mensagem recebida via SMTP.

E se quisermos incluir uma imagem em nosso HTML ? Algumas pessoas publicam a imagem na internet e referenciam o link dela no HTML da mensagem. Mas essa solução exige que o destinatário esteja conectado para poder buscar a imagem, coisa que nem sempre é verdade. Numa empresa, por exemplo, as mensagens são recebidas de forma centralizada por um servidor de email, dispensando a necessidade de ter internet local. Muitas delas adotam ainda restrições ao acesso à internet.

Uma maneira melhor de se fazer isso é enviar a imagem junto com o HTML. Ao invés de preencher o campo Body da mensagem, teremos que decompô-la em seus constituintes básicos para podermos identificar de forma separada o MIME de cada um. Isto é, o corpo da mensagem é um HTML enquanto a imagem é um arquivo binário com MIME próprio. O conjunto todo terá um MIME especial (multipart/mixed) que sinaliza que a mensagem está montada como múltiplas partes independentes.

Cada parte deverá ser anexada à mensagem através da propriedade MessageParts. Para o corpo, usamos o tipo TIdText. Para a imagem, o tipo tradicional para anexos (TIdAttachmentFile).
var
text : TIdText;
at : TIdAttachmentFile;
begin
IdMessage1.MessageParts.Clear();
IdMessage1.ContentType := 'multipart/mixed';

text := TIdText.Create (IdMessage1->MessageParts, Nil);
text.ContentType := 'text/html';
text.CharSet := 'ISO-8859-1';
text.Body.Text := PreparaHTML();

at := TIdAttachmentFile.Create (IdMessage1->MessageParts,
'C:\\Inetpub\\wwwroot\\winxp.gif');
at.ContentType := 'image/gif';
at.FileName := 'winxp.gif';

IdSMTP1.Connect();
IdSMTP1.Send(IdMessage1);
{ ... }

O HTML pode, então, fazer referência diretamente ao nome do arquivo anexado, sem precisar estipular um endereço na internet. A única coisa é que o nome do arquivo deve ser exatamente igual àquele informado na propriedade FileName do anexo:
function TForm1.PreparaHTML : String;
begin
{ ... }
Result := Result + '<img style="margin:1px 1px 1px 0px;" src="winxp.gif" />';
{ ... }
end;

Em tese, não há restrição a quantos recursos externos podem ser agregados ao email usando esse tipo de construção. Também não se restringe à inclusão de imagens, podendo ser usado para incorporar animações, scripts, folhas de estilo, etc. - desde que tenham os respectivos MIMEs devidamente configurados.

Estou com a versão 10 do Indy que vem com o Delphi XE mas acredito que os recursos mostrados aqui estejam disponíveis em versões anteriores também.

Mais Informações
Enviando emails com Delphi

5 de maio de 2011

Invenção da Intel amplia sobrevida da base tecnológica dos atuais transístores

Já vi e ouvi em mais de uma fonte que o limite da miniaturização dos componentes eletrônicos está chegando ao seu limite, imposto pela impossibilidade física de se manipular algo menor do que um átomo. Quer dizer, o menor transístor possível, no limite, seria em tese um único átomo.

É uma implicação natural da lei de Moore, postulada em 1965 por Gordon Moore, co-fundador da Intel, e que diz que o número de transístores que podem ser inseridos num circuito integrado dobra a cada dois anos sem aumento de custos. Essa característida está intimamente ligada à capacidade de processamento dos aparelhos eletrônicos e quanta informação eles conseguem armazenar. Mas, uma hora não haverá mais espaço físico para aumentar a quantidade de transístores num chip ...

Com isso, especula-se muito que tecnologia substituirá aquela na qual os atuais transístores se baseiam. Talvez algo que explore a mecânica quântica ou que seja baseado nas propriedades da luz.

Mas, não é que a Intel ainda está conseguindo avançar com o bom e velho silício mesmo ? Essa semana, eles anunciaram que vão dar início à produção de chips cujos transístores são construídos numa nova arquitetura, tridimensional, que é mais eficiente e mais econômica do que a atualmente em uso e que é montada num plano (arquitetura bidimensional).

O texto que vai abaixo é reportagem da ComputerWorld que aborda a "reinvenção dos transistores" pela Intel, usando tecnologia 3D.

A Intel anunciou nesta quarta-feira o que considera um avanço significativo na evolução do transistor, o componente que há mais de 50 anos é a pedra-fundamental da indústria eletrônica. A empresa irá iniciar a produção em larga escala de chips baseados em um transistor com design "tridimensional", que possibilita melhor desempenho e menor consumo de energia quando comparado aos transistores "planos" atuais.

O design foi batizado pela empresa de "Tri-Gate", e originalmente apresentado em 2002. Produzidos em um processo de 22 nanômetros, os novos componentes tem desempenho 37 por cento superior aos componentes de 32 nm utilizados atualmente em processadores como os da família "Sandy Bridge" quando operando em baixa voltagem. Quando operando no mesmo nível de desempenho dos transistores atuais, os "Tri-Gate" tem consumo de energia até 50% menor.

Transistores operam como interruptores: o fluxo da corrente elétrica é controlado por uma parte chamada Gate (comporta), que permite ou não a passagem de energia em um canal entre a fonte (Source) e o dreno (Drain).

O design Tri-Gate substitui o canal plano e um único Gate sobre ele por uma fina lâmina de silício que se projeta acima do substrato do transistor, envolta por três Gates (dois nos lados, um no topo). O controle extra permite fluxo máximo de corrente quando o transistor está "ligado" (o que ajuda o desempenho), e o mínimo possível quando desligado (reduzindo o desperdício de energia), além de permitir que o componente alterne rapidamente entre os dois estados.

Transistor plano X Transistor 3D
Esta ilustração compara um transistor plano (esquerda) a um Tri-Gate (direita)

A próxima geração de processadores Intel, de codinome "Ivy Bridge", será a primeira a utilizar os novos transistores Tri-Gate. A Intel demonstrou hoje notebooks, desktops e servidores operando com processadores "Ivy Bridge", que devem entrar em produção em larga escala no final deste ano. Graças à tecnologia Tri-Gate a empresa espera produzir chips com transistores em processo de 14 nanômetros em 2013, e 10 nanômetros em 2015.

O link para a reportagem original está disponível no quadro abaixo.

29 de abril de 2011

Design Patterns com Delphi: Observer - Parte II

No post anterior, apresentei o tipo de problema que o Design Pattern comportamental Observer se propõe a resolver, introduzindo os conceitos envolvidos na implementação de uma solução. Aqui, mostro uma sugestão de como efetivamente implementá-lo em projetos Delphi.

Dependendo do contexto onde o padrão Observer será empregado, a implementação dele poderá sofrer ligeiras variações. Uma das diferença mais comuns está relacionada a quantas instâncias de classes poderão ser notificadas sobre um mesmo evento. Eventos da VCL, por exemplo, podem ser respondidos por no máximo uma única função, vinculada a uma classe. Por isso, uma variável simples é o bastante para conter a referência da função que será chamada. Já no exemplo que aparece no post anterior, diversos usuários podem requerer notificação para a mesma atualização num objeto de negócio. Por isso, nossa implementação precisará armazenar os observers em algum tipo de lista.

Para facilitar, reproduzo abaixo o diagrama UML representando a proposta de implementação do exemplo do post anterior:
Diagrama UML para o padrão Observer

Pelo diagrama, a classe que define o comportamento base de todo Subject é a TWBusinessObj. É ela, portanto, quem tem que ser capaz de armazenar as instâncias dos Observer que receberão avisos de alteração. Veja no código abaixo que o controle de quais instâncias devem receber os avisos é feito com uma lista de objetos, ou seja, tantas instâncias quantas forem necessárias podem "assinar" o serviço e serem avisadas :
TWBOState=class;
TWBOObserver=class;

TWBusinessObj=class
protected
_ListaObsv : TObjectList;
{ ... }
public
procedure AttachObsv (AObsv: TWBOObserver);
procedure DetachObsv (AObsv: TWBOObserver);
procedure Notify;

function getState: TWBOState;virtual;abstract;

{ ... }

Constructor Create;
Destructor Destroy;override;
end;

implementation

Constructor TWBusinessObj.Create;
begin
_ListaObsv := TObjectList.Create (false);
end;

Destructor TWBusinessObj.Destroy;
begin
FreeAndNil (_ListaObsv);
inherited;
end;

procedure TWBusinessObj.AttachObsv (AObsv: TWBOObserver);
begin
_ListaObsv.Add(AObsv);
end;

procedure TWBusinessObj.DetachObsv (AObsv: TWBOObserver);
begin
_ListaObsv.Remove(AObsv);
end;

procedure TWBusinessObj.Notify;
var i : integer;
lObsv : TWBOObserver;
begin
for i := 0 to _ListaObsv.Count - 1 do
try
lObsv := _ListaObsv.Items [i] As TWBOObserver;
lObsv.Update(Self);
except
end;
end;

Há outros detalhes para prestar atenção. O construtor da lista recebe um parâmetro com valor false para indicar que ela não é responsável por devolver a memória utilizada pelos objetos que ela contém. Isso não pode acontecer pois ainda podemos precisar dos objetos inseridos na lista mesmo que o TWBusinessObj seja deletado. Lembre-se de que, neste exemplo, os objetos que receberão as notificações são instâncias que representam usuários no sistema e que eles podem requerer notificações de vários objetos de negócio diferentes ao mesmo tempo.

Um outro ponto é que a classe TWBusinessObj é abstrata e, portanto, não poderá ser diretamente instanciada. Cada herança dela precisará remover a abstração, implementando a função getState para fornecer informações específicas sobre o estado interno de suas propriedades. Veja um exemplo:
TWPedidoVenda=class(TWBusinessObj)
protected
{ ... }
_State : TWBOState;
public
{ ... }
function getState : TWBOState;override;
procedure setDataEntrega (ADt: TDateTime);
end;

{ ... }
function TWPedidoVenda.getState : TWBOState;
begin
Result := _State;
end;

procedure TWPedidoVenda.setDataEntrega (ADt: TDateTime);
begin
_State.ModifyProperty ('DT_ENTREGA', ADt);
Notify;
end;

A classe TWBOState que aparece nesse código é uma base que eu montei para conter as informações de estado específicas de cada objeto de negócio, permitindo recuperar o valor atual de cada propriedade e aquele que havia antes, caso ela tenha sofrido uma alteração. No trecho mostrado acima, uma instância dessa classe registra a alteração na data de entrega do pedido e, em seguida, o próprio pedido dispara notificações dessa alteração usando a função Notify mostrada no primeiro quadro desse post.

Fica faltando, então, a segunda parte da operação: fazer com que cada Observer interprete como lhe for conveniente as modificações notificadas, implementando a função Update:
TWBOObserver=class
public
procedure Update (AObj: TWBusinessObj);virtual;abstract;
end;

TWAuditoria=class(TWBOObserver)
public
procedure Update (AObj: TWBusinessObj);override;
end;

TWUsuario=class(TWBOObserver)
public
procedure Update (AObj: TWBusinessObj);override;
end;

{ ... }

procedure TWAuditoria.Update (AObj: TWBusinessObj);
var lState : TWBOState;
begin
lState := AObj.getState();
GravaAuditoria (lState);
end;

procedure TWUsuario.Update (AObj: TWBusinessObj);
var lState : TWBOState;
begin
lState := AObj.getState();
EnviaEMail (lState);
end;

Em algum ponto do sistema teremos que usar a função AttachObsv para vincular a classe de auditoria e os usuários apropriados, isto é, fazer com que essas classes "assinem" o serviço de notificação de um objeto de negócio:
var _Auditoria : TWAuditoria;
_Gerente : TWUsuario;
{ ... }
Constructor TWFormVenda.Create (AOwner: TComponent);
begin
inherited;
_Pedido := TWPedidoVenda.Create;
_Pedido.AttachObsv (_Auditoria);
_Pedido.AttachObsv (_Gerente);
{ ... }
end;

O planejamento do exemplo incluiu ainda a possibilidade de uma classe cancelar a assinatura, suspendendo as notificações para si. Para isso, basta chamar a função DetachObsv quando (e se) for necessário.