PDA

Ver la Versión Completa : Ocultar destinatarios


maxvera
14-09-2007, 20:02:50
Saludos para el Foro.

Tengo esta función para enviar e-mails desde mi aplicación:

function SendMail(Handle: THandle; Mail: TStrings): Cardinal;
type
TAttachAccessArray = array [0..0] of TMapiFileDesc;
PAttachAccessArray = ^TAttachAccessArray;
var
MapiMessage: TMapiMessage;
Receip: TMapiRecipDesc;
Attachments: PAttachAccessArray;
AttachCount: Integer;
i1: integer;
FileName: string;
dwRet: Cardinal;
MAPI_Session: Cardinal;
WndList: Pointer;
begin
dwRet := MapiLogon(Handle,
PChar(''),
PChar(''),
MAPI_LOGON_UI or MAPI_NEW_SESSION,
0, @MAPI_Session);
if (dwRet <> SUCCESS_SUCCESS) then begin
MessageBox(Handle,
PChar(_('Error while trying to send email')),
PChar(_('Error')),
MB_ICONERROR or MB_OK);
end else begin
FillChar(MapiMessage, SizeOf(MapiMessage), #0);
Attachments := nil;
FillChar(Receip, SizeOf(Receip), #0);
if Mail.Values['to'] <> '' then begin
Receip.ulReserved := 0;
Receip.ulRecipClass := MAPI_TO;
Receip.lpszName := StrNew(PChar(Mail.Values['to']));
Receip.lpszAddress := StrNew(PChar('SMTP:' + Mail.Values['to']));
Receip.ulEIDSize := 0;
MapiMessage.nRecipCount := 1;
MapiMessage.lpRecips := @Receip;
end;
AttachCount := 0;
for i1 := 0 to MaxInt do begin
if Mail.Values['attachment' + IntToStr(i1)] = ''
then Break;
Inc(AttachCount);
end;
if AttachCount > 0 then
begin
GetMem(Attachments, SizeOf(TMapiFileDesc) * AttachCount);
for i1 := 0 to AttachCount - 1 do begin
FileName := Mail.Values['attachment' + IntToStr(i1)];
Attachments[i1].ulReserved := 0;
Attachments[i1].flFlags := 0;
Attachments[i1].nPosition := ULONG($FFFFFFFF);
Attachments[i1].lpszPathName := StrNew(PChar(FileName));
Attachments[i1].lpszFileName :=
StrNew(PChar(ExtractFileName(FileName)));
Attachments[i1].lpFileType := nil;
end;
MapiMessage.nFileCount := AttachCount;
MapiMessage.lpFiles := @Attachments^;
end;
if Mail.Values['subject'] <> ''
then MapiMessage.lpszSubject := StrNew(PChar(Mail.Values['subject']));
if Mail.Values['body'] <> ''
then MapiMessage.lpszNoteText := StrNew(PChar(Mail.Values['body']));
WndList := DisableTaskWindows(0);
try
Result := MapiSendMail(MAPI_Session, Handle,
MapiMessage, MAPI_DIALOG, 0);
finally
EnableTaskWindows(WndList);
end;
for i1 := 0 to AttachCount - 1 do
begin
StrDispose(Attachments[i1].lpszPathName);
StrDispose(Attachments[i1].lpszFileName);
end;
if Assigned(MapiMessage.lpszSubject)
then StrDispose(MapiMessage.lpszSubject);
if Assigned(MapiMessage.lpszNoteText)
then StrDispose(MapiMessage.lpszNoteText);
if Assigned(Receip.lpszAddress)
then StrDispose(Receip.lpszAddress);
if Assigned(Receip.lpszName)
then StrDispose(Receip.lpszName);
MapiLogOff(MAPI_Session, Handle, 0, 0);
end;
end;


Funciona de maravilla, pero me gustaría poder ocultar la lista completa de destinatarios a cada destinatario individual.



Sé que tengo que utilizar algo relacionado con cc (carbon copy) pero no tengo ni idea de cómo implementarlo.

Agradecería cualquier ayuda de expertos en MAPI

Casimiro Notevi
14-09-2007, 21:18:12
[..]
if Mail.Values['to'] <> '' then begin Receip.ulReserved := 0; Receip.ulRecipClass := MAPI_TO; Receip.lpszName := StrNew(PChar(Mail.Values['to']));
Receip.lpszAddress := StrNew(PChar('SMTP:' + Mail.Values['to']));
Receip.ulEIDSize := 0;
MapiMessage.nRecipCount := 1;
MapiMessage.lpRecips := @Receip;
end;
[..]

Te lo confirmo mañana desde el trabajo, porque tengo el código allí, pero tiene algo que ver con:
if Mail.Values['to'] <> '' then beginQue será algo así como:
if Mail.Values['bcc'] <> '' then begin

maxvera
16-09-2007, 19:02:25
Gracias por la respuesta, Rompe.

He cambiado este bloque en la función:

if Mail.Values['to'] <> '' then begin
Receip.ulReserved := 0;
Receip.ulRecipClass := MAPI_TO;
Receip.lpszName := StrNew(PChar(Mail.Values['to']));
Receip.lpszAddress := StrNew(PChar('SMTP:' + Mail.Values['to']));
Receip.ulEIDSize := 0;
MapiMessage.nRecipCount := 1;
MapiMessage.lpRecips := @Receip;
end;

Por este otro:

if Mail.Values['bcc'] <> '' then begin
Receip.ulReserved := 0;
Receip.ulRecipClass := MAPI_BCC;
Receip.lpszName := StrNew(PChar(Mail.Values['bcc']));
Receip.lpszAddress := StrNew(PChar('SMTP:' + Mail.Values['bcc']));
Receip.ulEIDSize := 0;
MapiMessage.nRecipCount := 1;
MapiMessage.lpRecips := @Receip;
end;

Las direcciones a las que quiero enviar y la llamada a la función las genero con este código:

maillist := TStringList.Create;
with DM.QrMailSelect do begin
First;
while not eof do begin
if Trim(DM.QrMailSelectFnE_mail.Value) <> ''
then maillist.values['bcc'] := maillist.values['bcc'] + ';' +
DM.QrMailSelectFnE_mail.Value;
Next;
end;
maillist.values['bcc'] := StringReplace(maillist.values['bcc'], ';', '', []);
end;
try
maillist.values['subject'] := 'Document sending.';
sendMail(Application.Handle, maillist);
finally
maillist.Free;
end;

El resultado es un mensaje en el que no aparecen destinatarios ni en 'Para:' ni en 'C.c.:' y, como cabría esperar, al enviarlo no se manda a ningún sitio.

¿Qué se me escapa?

Gracias y saludos.

dec
16-09-2007, 19:38:35
Hola,

Pues que tiene que haber un "TO". O sea, un destinatario, al que ha de llegar el mensaje, y luego los destinatarios (ocultos o no) a los que deben llegar copias del mismo. Así que yo diría que tienes que usar el anterior código y el nuevo. Solo que en el anterior ("TO") no debes añadir sino un solo destinatario.

maxvera
17-09-2007, 02:28:51
Gracias David por tu respuesta.

He comprobado que la función hace su trabajo incluso sin el Receip['to'], pero siempre y cuando sólo haya una dirección de e-mail.

Si hay más de una, el cliente de correo me devuelve un error al intentar enviar el mensaje (con 'to' y sin 'to'). El error dice que no puede enviar a la dirección 'direcciondecorreo1;direcciondecorreo2;...;direcciondecorreoN'.

Es decir, parece como si interpretara la cadena de direcciones como una sola.

Aunque sigo pegao con el problema, me parece entender tras un análisis (?)que la función está preparada para un solo destinatario.

Esto me ha llevado a probarme (cual ciego, dando palos) y he desarrollado este nuevo código para la función:

function SendMail(Handle: THandle; Mail: TStrings): Cardinal;
type
TAttachAccessArray = array [0..0] of TMapiFileDesc;
PAttachAccessArray = ^TAttachAccessArray;
TDirecAccessArray = array [0..0] of TMapiRecipDesc;
PDirecAccessArray = ^TDirecAccessArray;
var
MapiMessage: TMapiMessage;
Receip: PDirecAccessArray;
Attachments: PAttachAccessArray;
AttachCount, DireccionesCount: Integer;
i1: integer;
FileName: string;
dwRet: Cardinal;
MAPI_Session: Cardinal;
WndList: Pointer;
begin
dwRet := MapiLogon(Handle,
PChar(''),
PChar(''),
MAPI_LOGON_UI or MAPI_NEW_SESSION,
0, @MAPI_Session);
if (dwRet <> SUCCESS_SUCCESS) then begin
MessageBox(Handle,
PChar(_('Error while trying to send email')),
PChar(_('Error')),
MB_ICONERROR or MB_OK);
end else begin
FillChar(MapiMessage, SizeOf(MapiMessage), #0);
Attachments := nil;
Receip := nil;
DireccionesCount := 0;
for i1 := 0 to MaxInt do begin
if Mail.Values['bcc' + IntToStr(i1)] = ''
then Break;
Inc(DireccionesCount);
end;
if DireccionesCount > 0 then
begin
GetMem(Receip, SizeOf(TMapiRecipDesc) * DireccionesCount);
// FillChar(Receip, SizeOf(TMapiRecipDesc) * DireccionesCount, #0);
for i1 := 0 to DireccionesCount - 1 do begin
Receip[i1].ulReserved := 0;
Receip[i1].ulRecipClass := MAPI_BCC;
Receip[i1].lpszName := StrNew(PChar(Mail.Values['bcc' + IntToStr(i1)]));
Receip[i1].lpszAddress := StrNew(PChar('SMTP:' +
Mail.Values['bcc' + IntToStr(i1)]));
Receip[i1].ulEIDSize := 0;
end;
MapiMessage.nRecipCount := DireccionesCount;
MapiMessage.lpRecips := @Receip;
end;
AttachCount := 0;
for i1 := 0 to MaxInt do begin
if Mail.Values['attachment' + IntToStr(i1)] = ''
then Break;
Inc(AttachCount);
end;
if AttachCount > 0 then
begin
GetMem(Attachments, SizeOf(TMapiFileDesc) * AttachCount);
for i1 := 0 to AttachCount - 1 do begin
FileName := Mail.Values['attachment' + IntToStr(i1)];
Attachments[i1].ulReserved := 0;
Attachments[i1].flFlags := 0;
Attachments[i1].nPosition := ULONG($FFFFFFFF);
Attachments[i1].lpszPathName := StrNew(PChar(FileName));
Attachments[i1].lpszFileName :=
StrNew(PChar(ExtractFileName(FileName)));
Attachments[i1].lpFileType := nil;
end;
MapiMessage.nFileCount := AttachCount;
MapiMessage.lpFiles := @Attachments^;
end;
if Mail.Values['subject'] <> ''
then MapiMessage.lpszSubject := StrNew(PChar(Mail.Values['subject']));
if Mail.Values['body'] <> ''
then MapiMessage.lpszNoteText := StrNew(PChar(Mail.Values['body']));
WndList := DisableTaskWindows(0);
try
Result := MapiSendMail(MAPI_Session, Handle,
MapiMessage, MAPI_DIALOG, 0);
finally
EnableTaskWindows(WndList);
end;
for i1 := 0 to DireccionesCount - 1 do
begin
if Assigned(Receip[i1].lpszAddress)
then StrDispose(Receip[i1].lpszAddress);
if Assigned(Receip[i1].lpszName)
then StrDispose(Receip[i1].lpszName);
end;
for i1 := 0 to AttachCount - 1 do
begin
StrDispose(Attachments[i1].lpszPathName);
StrDispose(Attachments[i1].lpszFileName);
end;
if Assigned(MapiMessage.lpszSubject)
then StrDispose(MapiMessage.lpszSubject);
if Assigned(MapiMessage.lpszNoteText)
then StrDispose(MapiMessage.lpszNoteText);
MapiLogOff(MAPI_Session, Handle, 0, 0);
end;
end;


Con el resultado bastante previsible de que, aunque recorre el código sin error, al final no hace nada. Y digo nada. No abre ni siquiera el cliente de correo.

En cuanto a la línea que está comentada, aclarar que con ella sí que generaba un error. La cambié por la inmediatamente superior (en otro memorable palo de ciego) y el error desapareció.

Lo dicho: estoy más pegao con este tema...

A ver si eres capaz de iluminarme como sueles.

Gracias y saludos.

dec
17-09-2007, 03:24:36
Hola,

No me queda claro si tú lo controlas, pero, prueba a separar los destinatarios mediante "comas" en lugar de "puntos y comas".

maxvera
17-09-2007, 04:38:26
Señor Esperalta:

He probado con coma, coma espacio, punto y coma, punto y coma espacio, espacio... y todo sigue igual.

Insisto, con una dirección funciona bien; con más de una no envía el mensaje xq dice no encontrar al destinatario.

la línea:

MapiMessage.nRecipCount := 1;


parece indicar que sólo admite un destinatario (¿qué opinas?), lo que haría nulos todos los intentos de usar cualquier tipo de separador entre direcciones.

Respecto a Seoane, he estado en su página, pero no he visto ningún artículo sobre el particular.

¿Alguna otra idea?

Gracias de nuevo.

dec
17-09-2007, 04:54:21
Hola,

Pues lamento decirte que yo nunca he usado MAPI, y no parece algo como para ponerse en un rato... sin embargo, buscando en Google (http://www.google.es/search?hl=es&q=Send+Blind+copy+with+MAPI+Delphi&btnG=Buscar+con+Google&meta=), el primer resultado (actualmente) es el artículo How to send email using the MAPI (http://www.delphi3000.com/articles/article_1230.asp?SK=) en Delphi 3000 (http://www.delphi3000.com/) (requiere registro gratuito, probablemente). Y me he parado ahí, porque, en el artículo se presenta un componente que hace de "envoltorio" a MAPI, y, entre otras cosas, dicho componente permite el envío del correo a múltiples destinatarios...

No lo he mirado sino hasta ahí. He pensado que tal vez podrías estudiar el funcionamiento de dicho componente, y, o bien usarlo sin más, o bien adaptar su código o parte de él a tus necesidades. Ya te digo que yo ahora mismo poco o nada puedo decir sobre MAPI y su funcionamiento. Lo siento.


Respecto a Seoane, he estado en su página, pero no he visto ningún artículo sobre el particular.


Je, je, je... bueno. En realidad la referencia está en mi firma, no es que te lo dijera a ti expresamente. Además, tal vez no sobre MAPI (aún), pero, seguro que puedes encontrar cosas muy curiosas en la Web de Seoane (http://delphi.jmrds.com/). :)

maxvera
17-09-2007, 04:57:41
Allá voy.

Muchas gracias por tu interés.

Si lo soluciono haré otro post con el código final (por si a alguien pudiera interesar).

Saludos.

maxvera
17-09-2007, 09:08:20
Bien. La función (que funciona) queda así:

(Añadir la unidad MAPI al uses del formulario);

function SendMail(Handle: THandle; Mail: TStrings): Cardinal;
type
TAttachAccessArray = array [0..0] of TMapiFileDesc;
PAttachAccessArray = ^TAttachAccessArray;
TDirecAccessArray = array [0..0] of TMapiRecipDesc;
PDirecAccessArray = ^TDirecAccessArray;
var
MapiMessage: TMapiMessage;
Receip: PDirecAccessArray;
Attachments: PAttachAccessArray;
AttachCount, DireccionesCount: Integer;
i1: integer;
FileName: string;
dwRet: Cardinal;
MAPI_Session: Cardinal;
WndList: Pointer;
begin
dwRet := MapiLogon(Handle,
PChar(''),
PChar(''),
MAPI_LOGON_UI or MAPI_NEW_SESSION,
0, @MAPI_Session);
if (dwRet <> SUCCESS_SUCCESS) then begin
MessageBox(Handle,
PChar(_('Error while trying to send email')),
PChar(_('Error')),
MB_ICONERROR or MB_OK);
end else begin
FillChar(MapiMessage, SizeOf(MapiMessage), #0);
Attachments := nil;
Receip := nil;
DireccionesCount := 0;
for i1 := 0 to MaxInt do begin
if Mail.Values['bcc' + IntToStr(i1)] = ''
then Break;
Inc(DireccionesCount);
end;
if DireccionesCount > 0 then
begin
GetMem(Receip, SizeOf(TMapiRecipDesc) * DireccionesCount);
for i1 := 0 to DireccionesCount - 1 do begin
Receip[i1].ulReserved := 0;
Receip[i1].ulRecipClass := MAPI_BCC;
Receip[i1].lpszName := StrNew(PChar(Mail.Values['bcc' + IntToStr(i1)]));
Receip[i1].lpszAddress := StrNew(PChar('SMTP:' +
Mail.Values['bcc' + IntToStr(i1)]));
Receip[i1].ulEIDSize := 0;
end;
MapiMessage.nRecipCount := DireccionesCount;
MapiMessage.lpRecips := @Receip^;
end;
AttachCount := 0;
for i1 := 0 to MaxInt do begin
if Mail.Values['attachment' + IntToStr(i1)] = ''
then Break;
Inc(AttachCount);
end;
if AttachCount > 0 then
begin
GetMem(Attachments, SizeOf(TMapiFileDesc) * AttachCount);
for i1 := 0 to AttachCount - 1 do begin
FileName := Mail.Values['attachment' + IntToStr(i1)];
Attachments[i1].ulReserved := 0;
Attachments[i1].flFlags := 0;
Attachments[i1].nPosition := ULONG($FFFFFFFF);
Attachments[i1].lpszPathName := StrNew(PChar(FileName));
Attachments[i1].lpszFileName :=
StrNew(PChar(ExtractFileName(FileName)));
Attachments[i1].lpFileType := nil;
end;
MapiMessage.nFileCount := AttachCount;
MapiMessage.lpFiles := @Attachments^;
end;
if Mail.Values['subject'] <> ''
then MapiMessage.lpszSubject := StrNew(PChar(Mail.Values['subject']));
if Mail.Values['body'] <> ''
then MapiMessage.lpszNoteText := StrNew(PChar(Mail.Values['body']));
WndList := DisableTaskWindows(0);
try
Result := MapiSendMail(MAPI_Session, Handle,
MapiMessage, MAPI_DIALOG, 0);
finally
EnableTaskWindows(WndList);
end;
for i1 := 0 to DireccionesCount - 1 do
begin
if Assigned(Receip[i1].lpszAddress)
then StrDispose(Receip[i1].lpszAddress);
if Assigned(Receip[i1].lpszName)
then StrDispose(Receip[i1].lpszName);
end;
for i1 := 0 to AttachCount - 1 do
begin
StrDispose(Attachments[i1].lpszPathName);
StrDispose(Attachments[i1].lpszFileName);
end;
if Assigned(MapiMessage.lpszSubject)
then StrDispose(MapiMessage.lpszSubject);
if Assigned(MapiMessage.lpszNoteText)
then StrDispose(MapiMessage.lpszNoteText);
MapiLogOff(MAPI_Session, Handle, 0, 0);
end;
end;


Y el código para los archivos adjuntos y los destinatarios podría ser este:

maillist := TStringList.Create;
direcciones := TStringList.Create;
with DM.QrMailSelect do begin
First;
while not eof do begin
if Trim(DM.QrMailSelectFnE_mail.Value) <> ''
then direcciones.Append(DM.QrMailSelectFnE_mail.Value);
Next;
end;
end;
for i := 0 to direcciones.Count - 1
do maillist.values['bcc' + IntToStr(i)] := direcciones.Strings[i];
try
maillist.values['subject'] := _('Document sending.');
for i := 0 to documentos.Count - 1
do maillist.values['attachment' + IntToStr(i)] := documentos.Strings[i];
sendMail(Application.Handle, maillist);
finally
maillist.Free;
direcciones.Free;
end;


Donde documentos es un stringlist que le paso en otro procedimiento.

Funciona perfectamente con todos los destinatarios ocultos, aunque se podría completar incluyendo también destinatarios 'to' y 'cc'.

Los grupos '_(' en el código forman parte del gnugettext. En el caso de no estar usando tal soporte, basta con eliminarlos.

Gracias a dec por su apoyo.