Jump to content

HowTo : send mail


mierlp

Recommended Posts

Hi,

 

I was wondering how you send e-mail. I know Indy can be used, but i find in not the best solution

for my Win32 applications so i switched to AddEmail from Traysoft. A nice feature is that you can

import a html file into the body of the message. Using FastReport the user could create a report

for his e-mail body. The report was exported to html and then imported into the e-mail message body.

 

AddEmail is a active X and you have several non visual components which can be used with uniGui

 

Questions:

- how do you facilitate composing/sending a single mail to a user...do you have a self build

mail form? normally i used the shellexecute for calling the default mail client...in web mode

that's not what you want

- how do facilitate composing/sending bulk mail to all clients within you database?

 

Tips...suggestions..ideas, samples are welcome

 

 

Regards Peter

Link to comment
Share on other sites

Hi,

Compose the mail and store to database, once the mail is ready to be send, call the mail sender, see the code

unit MailsForm;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, uniGUITypes, uniGUIAbstractClasses, uniGUIClasses, uniGUIForm, StrUtils, IdCoderMIME, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdExplicitTLSClientServerBase, IdMessageClient, IdSMTPBase, IdSMTP, IdMessage, IdAttachment, IdAttachmentFile, IdText, DB, ADODB, uniGUIBaseClasses, uniButton;



type
TFormMails = class(TUniForm)
QryMain: TADOQuery;
QryMainEmailId: TAutoIncField;
QryMainFolder: TIntegerField;
QryMainTagIO: TStringField;
QryMainRefDate: TDateTimeField;
QryMainSize: TIntegerField;
QryMainFromEmail: TMemoField;
QryMainToEmail: TMemoField;
QryMainCCEmail: TMemoField;
QryMainBCCEmail: TMemoField;
QryMainSubject: TMemoField;
QryMainBody: TMemoField;
QryMainRawMsg: TBlobField;
QryMainIsSubmitted: TBooleanField;
QryMainIsSent: TBooleanField;
QryMainSentDate: TDateTimeField;
QryMainUsersId: TIntegerField;
QryMainIsReaded: TBooleanField;
QryMainMainId: TAutoIncField;
QryMainTndrId: TIntegerField;
QryDetailA: TADOQuery;
QryDetailAEmailDetId: TAutoIncField;
QryDetailAEmailId: TIntegerField;
QryDetailAAtchFileName: TStringField;
QryDetailAAtchFileData: TBlobField;
QryDetailAAtchSize: TIntegerField;
QryDetailAMainId: TIntegerField;
ButtonSendMail: TUniButton;
procedure ButtonSendMailClick(Sender: TObject);

private
procedure SendHtmlMail;
procedure ProcessHtml(var HBody: WideString; AtchList: TStringList);
procedure Decode2File(const base64: String; const FileName: string);
function MyBase64Decode(const EncodedText: string): TBytes;
{ Private declarations }
public
{ Public declarations }
end;

implementation

uses
uniGUIApplication, ServerModule, MainModule;

{$R *.dfm}

{ TUniForm1 }
procedure TFormMails.ButtonSendMailClick(Sender: TObject);
begin
if not (QryMain.State in [dsInsert,dsEdit]) then QryMain.Edit;
QryMainIsSubmitted.Value:=True;
QryMain.Post;
if (not QryMainIsSent.AsBoolean) and (QryMainIsSubmitted.AsBoolean) then
SendHtmlMail();
end;

procedure TFormMails.Decode2File(const base64, FileName: string);
var
stream: TFileStream;
bytes: TBytes;
begin
bytes := MyBase64Decode(base64);
stream := TFileStream.Create(FileName, fmCreate);
try
if bytes<>nil then
stream.Write(bytes[0], Length(Bytes));
finally
stream.Free;
end;
end;

function TFormMails.MyBase64Decode(const EncodedText: string): TBytes;
var
DecodedStm: TBytesStream;
Decoder: TIdDecoderMIME;
begin
Decoder := TIdDecoderMIME.Create(nil);
try
DecodedStm := TBytesStream.Create;
try
Decoder.DecodeBegin(DecodedStm);
Decoder.Decode(EncodedText);
Decoder.DecodeEnd;
Result := DecodedStm.Bytes;
SetLength(Result, DecodedStm.Size);
finally
DecodedStm.Free;
end;
finally
Decoder.Free;
end;

end;

procedure TFormMails.ProcessHtml(var HBody: WideString; AtchList: TStringList);
var
sHtm,sBase: WideString;
i,iCid,iPart,klen: integer;
sKey,TmpAtchfile: String;
bSkip:Boolean;
begin
AtchList.Clear;
sHtm := QryMainBody.AsString;
sKey := '<img src="data:';
klen := length(sKey);
bSkip:= False;
iCid := 0;
HBody:= '';
sBase:= '';
iPart:= 1;
for i:=1 to Length(sHtm) do begin
if iPart=1 then
HBody:=HBody +sHtm[i]
else if iPart=2 then begin
if not bSkip then sBase:=sBase +sHtm[i];
if (RightStr(sBase,7)= 'base64,') then sBase:='';
if (RightStr(sBase,6)= '" alt=') then begin
SetLength(sBase,length(sBase)-6);
bSkip:=True;
end;
end;
if (iPart=1) and (RightStr(HBody, klen)=sKey) then
iPart:=2
else if (iPart=2) and (sHtm[i]='>') then begin
iPart:=1;
bSkip:=False;
SetLength(HBody, length(HBody)-5);
HBody := HBody +'cid:ImgID' +InttoStr(iCid) +'">';
TmpAtchfile := UniServerModule.LocalCachePath +'Tmp'+InttoStr(iCid);
Decode2File(sBase, pchar(TmpAtchfile));
sBase:='';
AtchList.Add(TmpAtchfile);
iCid:=iCid+1;
end;
end;
end;

procedure TFormMails.SendHtmlMail;
var
i:Integer;
HtmPart, TxtPart: TIdText;
BmpPart: TIdAttachment;
Msg: TIdMessage;
IdSMTP: TIdSMTP;
AtchFile, sSql: String;
sHBody: WideString;
AtchList: TStringList;
begin
sHBody:='';
AtchList:= TStringList.Create;
ProcessHtml(sHBody, AtchList);
Msg := TIdMessage.Create(nil);
Msg.From.address := QryMainFromEmail.AsString;
Msg.Recipients.EMailAddresses := QryMainToEmail.AsString;
Msg.CCList.EMailAddresses := QryMainCCEmail.AsString;
Msg.BccList.EMailAddresses := QryMainBCCEmail.AsString;
Msg.Subject := QryMainSubject.AsString;
Msg.ContentType := 'multipart/alternative';
TxtPart := TIdText.Create(Msg.MessageParts);
TxtPart.ContentType := 'text/plain';
TxtPart := TIdText.Create(Msg.MessageParts);
TxtPart.ContentType := 'multipart/related; type="text/html"';

HtmPart := TIdText.Create(Msg.MessageParts, nil);
HtmPart.ContentType := 'text/html';
HtmPart.Body.Add('<html>');
HtmPart.Body.Add('<head>');
HtmPart.Body.Add('</head>');
HtmPart.Body.Add('<body>');
HtmPart.Body.Add(sHBody);
HtmPart.Body.Add('</body>');
HtmPart.Body.Add('</html>');
HtmPart.ParentPart := 1;
for i:=0 to AtchList.Count-1 do begin
BmpPart := TIdAttachmentFile.Create(Msg.MessageParts, pchar(AtchList[i]));
BmpPart.ContentType := 'image/jpeg';
BmpPart.ContentDisposition := 'inline';
BmpPart.ContentID := 'ImgID'+ IntToStr(i);
BmpPart.ParentPart := 1;
end;

Msg.ContentType := 'multipart/mixed';
QryDetailA.First;
while not QryDetailA.Eof do begin
AtchFile := UniServerModule.LocalCachePath +QryDetailAAtchFileName.AsString;
QryDetailAAtchFileData.SaveToFile(PChar(AtchFile));
TIdAttachmentFile.Create(Msg.MessageParts, AtchFile);
QryDetailA.Next;
end;
IdSMTP := TIdSMTP.Create(nil);
with UniMainModule do begin
idSMTP.Username := QryFirmSmtpUser.AsString;
idSMTP.Password := QryFirmSmtpPw.AsString;
idSMTP.Host := QryFirmSmtpHost.AsString;
idSMTP.Port := QryFirmSmtpPort.AsInteger;
end;
try
idSMTP.Connect();
try
idSMTP.Send(Msg);
sSql:= 'UPDATE Email SET Folder = 1, IsSent = 1, SentDate = GETDATE() WHERE (EmailId=0';
sSql:= sSql +QryMainMainId.AsString +')';
UniMainModule.Conn.Execute(Pchar(sSql));
ShowMessage('Message Sent');
except
on E: Exception do ShowMessage('Failed: ' + E.Message);
end;
finally
if IdSMTP.Connected then idSMTP.Disconnect();
Msg.Free;
IdSMTP.Free;
AtchList.Clear;
AtchList.Free;
end;
end;

end.

TestEMails.rar

TestRetriveMails.rar

Link to comment
Share on other sites

Hi Oliver,

 

Thanks for sharing...looks very nice/good.

 

How do you send bulk mail and do you use

some kind of mail merge...integrate some

personal values from a database ?

 

Regards Peter

 

 

 

My current test version looks like this:

 

post-147-0-15355600-1357137791.png

 

post-147-0-47624300-1357137764.png

Link to comment
Share on other sites

How do you send bulk mail and do you use

some kind of mail merge...integrate some

personal values from a database ?

 

Not at present, but it is planned for the future.

 

I think i will simply have a text like "dear [NAME], ..." and then replace [NAME] and more by a sql query...

 

I don't know at this time if we will need master/detail-relations (e.g. invoice items) in the email or sending such things as PDF-Attachment. But i have developped such a behavior (master/detail with text replacing) a few years ago for a RTF-Report. It works, but is too difficult for most users, so we must deliver the "reports" (sql-relations, ...).

Link to comment
Share on other sites

Hi Oliver,

 

Within our Windows applications we only used 'standard' mail messages.

Those 'messages/layout' are created in FastReport as a report, so the user

can access all database and fields he needs. When they send a message the

report was automaticly exported to a mail.html file which was imported into

te mail body.

In this case the user can make his 'message' he wants, including images,

text, colors etc.

 

Works fine...but not in uniGui mode...that's also the reason about my

other thread 'How facilitate reporting'. I have also used 'search/replace'

but it's to difficult for users.

 

Regards Peter

 

 

 

Not at present, but it is planned for the future.

 

I think i will simply have a text like "dear [NAME], ..." and then replace [NAME] and more by a sql query...

 

I don't know at this time if we will need master/detail-relations (e.g. invoice items) in the email or sending such things as PDF-Attachment. But i have developped such a behavior (master/detail with text replacing) a few years ago for a RTF-Report. It works, but is too difficult for most users, so we must deliver the "reports" (sql-relations, ...).

Link to comment
Share on other sites

Hi Oliver

 

In this case they only need 1 query (record) -> 1 mail(body)

because we only need some fields out of the CONTACT database

like : LastName, FirstName, MiddeName

 

Regards Peter

Link to comment
Share on other sites

In this case they only need 1 query (record) -> 1 mail(body)

because we only need some fields out of the CONTACT database

like : LastName, FirstName, MiddeName

 

In this case it should be simple to give the user a TUniHmlMemo (or "tiny MCE" component) for editing the mail. The user must only insert things like [LastName] or you give him buttons to insert this. And then you must replace all [Fieldnames] with the value of the current record before sending.

Where do you have problems?

Link to comment
Share on other sites

Hi Oliver,

 

The problem then was the replacement from the [LastName] into real fieldnames so it

can be used with a query. Because the code was unuseless we did'nt used/saved it and found

other solutions.

 

I now build my 'simple' mail form (based on you're suggestion) so the user can send a e-mail.

For sending mail is prefer using stable components. I've tested the following components, which

are all working in Win32 but have some problems when using them in uniGui:

 

- Mailbee Smtp ActiveX (http://www.afterlogic.com/mailbee/objects

but have a problem (Componentent not connected tot a services) when i want the send the message the second time.

I used it in Win32 apps and it's a older version maybe a upgrade must be done and i will mail them about the error

- AddEmail ActiveX(http://www.traysoft.com/addemail_overview.htm

The problem here is a got a AccessViolation when a set the serialnumber for the component...even when i do it in

uniGui VCL mode...in a normal Win32 applications it's working. I've send them a mail for support.

 

Both components support a way of bullk mail...so if you have to send 500 mails to you're customers

 

 

Regards Peter

 

post-510-0-44361100-1357305437.png

Link to comment
Share on other sites

I now build my 'simple' mail form (based on you're suggestion) so the user can send a e-mail.

For sending mail is prefer using stable components. I've tested the following components, which

are all working in Win32 but have some problems when using them in uniGui:

- Mailbee Smtp ActiveX (http://www.afterlogic.com/mailbee/objects

but have a problem (Componentent not connected tot a services) when i want the send the message the second time.

I used it in Win32 apps and it's a older version maybe a upgrade must be done and i will mail them about the error

- AddEmail ActiveX(http://www.traysoft.com/addemail_overview.htm

The problem here is a got a AccessViolation when a set the serialnumber for the component...even when i do it in

uniGui VCL mode...in a normal Win32 applications it's working. I've send them a mail for support.

 

Have you tried to set "autocoinicialize" to true? (Autocoinitialize)

Link to comment
Share on other sites

Yep...did set it to TRUE, but didn't solved the problem.

There another strange behavior of the AddEmail Active X.

After i put the component on the form, save the project, reopen

the project the component is not visible any more and when

compeling i got the message :

 

Field FormMailBasic.SmtpMail does not have a corresponding component.

Remove the declaration Yes/No/Cancel

 

I think it's because the component has a big size icon wereby it's

'visual'

 

Regards Peter

 

Have you tried to set "autocoinicialize" to true? (Autocoinitialize)

Link to comment
Share on other sites

Hi Ronak,

 

Thanks for the tip...it was took some puzzle time, but i got

it working that way...great/thanks

 

Regards Peter

 

Hello,

 

Try, Creating the AddEmail Active-X object at run time and the set the required property values instead of dropping the component on the form at design time.

 

Regards

Link to comment
Share on other sites

  • 3 months later...
  • 2 weeks later...
  • 5 years later...
On 1/2/2013 at 7:25 AM, Ronak said:

Hi,

Compose the mail and store to database, once the mail is ready to be send, call the mail sender, see the code


unit MailsForm;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, uniGUITypes, uniGUIAbstractClasses, uniGUIClasses, uniGUIForm, StrUtils, IdCoderMIME, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdExplicitTLSClientServerBase, IdMessageClient, IdSMTPBase, IdSMTP, IdMessage, IdAttachment, IdAttachmentFile, IdText, DB, ADODB, uniGUIBaseClasses, uniButton;



type
TFormMails = class(TUniForm)
QryMain: TADOQuery;
QryMainEmailId: TAutoIncField;
QryMainFolder: TIntegerField;
QryMainTagIO: TStringField;
QryMainRefDate: TDateTimeField;
QryMainSize: TIntegerField;
QryMainFromEmail: TMemoField;
QryMainToEmail: TMemoField;
QryMainCCEmail: TMemoField;
QryMainBCCEmail: TMemoField;
QryMainSubject: TMemoField;
QryMainBody: TMemoField;
QryMainRawMsg: TBlobField;
QryMainIsSubmitted: TBooleanField;
QryMainIsSent: TBooleanField;
QryMainSentDate: TDateTimeField;
QryMainUsersId: TIntegerField;
QryMainIsReaded: TBooleanField;
QryMainMainId: TAutoIncField;
QryMainTndrId: TIntegerField;
QryDetailA: TADOQuery;
QryDetailAEmailDetId: TAutoIncField;
QryDetailAEmailId: TIntegerField;
QryDetailAAtchFileName: TStringField;
QryDetailAAtchFileData: TBlobField;
QryDetailAAtchSize: TIntegerField;
QryDetailAMainId: TIntegerField;
ButtonSendMail: TUniButton;
procedure ButtonSendMailClick(Sender: TObject);

private
procedure SendHtmlMail;
procedure ProcessHtml(var HBody: WideString; AtchList: TStringList);
procedure Decode2File(const base64: String; const FileName: string);
function MyBase64Decode(const EncodedText: string): TBytes;
{ Private declarations }
public
{ Public declarations }
end;

implementation

uses
uniGUIApplication, ServerModule, MainModule;

{$R *.dfm}

{ TUniForm1 }
procedure TFormMails.ButtonSendMailClick(Sender: TObject);
begin
if not (QryMain.State in [dsInsert,dsEdit]) then QryMain.Edit;
QryMainIsSubmitted.Value:=True;
QryMain.Post;
if (not QryMainIsSent.AsBoolean) and (QryMainIsSubmitted.AsBoolean) then
SendHtmlMail();
end;

procedure TFormMails.Decode2File(const base64, FileName: string);
var
stream: TFileStream;
bytes: TBytes;
begin
bytes := MyBase64Decode(base64);
stream := TFileStream.Create(FileName, fmCreate);
try
if bytes<>nil then
stream.Write(bytes[0], Length(Bytes));
finally
stream.Free;
end;
end;

function TFormMails.MyBase64Decode(const EncodedText: string): TBytes;
var
DecodedStm: TBytesStream;
Decoder: TIdDecoderMIME;
begin
Decoder := TIdDecoderMIME.Create(nil);
try
DecodedStm := TBytesStream.Create;
try
Decoder.DecodeBegin(DecodedStm);
Decoder.Decode(EncodedText);
Decoder.DecodeEnd;
Result := DecodedStm.Bytes;
SetLength(Result, DecodedStm.Size);
finally
DecodedStm.Free;
end;
finally
Decoder.Free;
end;

end;

procedure TFormMails.ProcessHtml(var HBody: WideString; AtchList: TStringList);
var
sHtm,sBase: WideString;
i,iCid,iPart,klen: integer;
sKey,TmpAtchfile: String;
bSkip:Boolean;
begin
AtchList.Clear;
sHtm := QryMainBody.AsString;
sKey := '<img src="data:';
klen := length(sKey);
bSkip:= False;
iCid := 0;
HBody:= '';
sBase:= '';
iPart:= 1;
for i:=1 to Length(sHtm) do begin
if iPart=1 then
HBody:=HBody +sHtm[i]
else if iPart=2 then begin
if not bSkip then sBase:=sBase +sHtm[i];
if (RightStr(sBase,7)= 'base64,') then sBase:='';
if (RightStr(sBase,6)= '" alt=') then begin
SetLength(sBase,length(sBase)-6);
bSkip:=True;
end;
end;
if (iPart=1) and (RightStr(HBody, klen)=sKey) then
iPart:=2
else if (iPart=2) and (sHtm[i]='>') then begin
iPart:=1;
bSkip:=False;
SetLength(HBody, length(HBody)-5);
HBody := HBody +'cid:ImgID' +InttoStr(iCid) +'">';
TmpAtchfile := UniServerModule.LocalCachePath +'Tmp'+InttoStr(iCid);
Decode2File(sBase, pchar(TmpAtchfile));
sBase:='';
AtchList.Add(TmpAtchfile);
iCid:=iCid+1;
end;
end;
end;

procedure TFormMails.SendHtmlMail;
var
i:Integer;
HtmPart, TxtPart: TIdText;
BmpPart: TIdAttachment;
Msg: TIdMessage;
IdSMTP: TIdSMTP;
AtchFile, sSql: String;
sHBody: WideString;
AtchList: TStringList;
begin
sHBody:='';
AtchList:= TStringList.Create;
ProcessHtml(sHBody, AtchList);
Msg := TIdMessage.Create(nil);
Msg.From.address := QryMainFromEmail.AsString;
Msg.Recipients.EMailAddresses := QryMainToEmail.AsString;
Msg.CCList.EMailAddresses := QryMainCCEmail.AsString;
Msg.BccList.EMailAddresses := QryMainBCCEmail.AsString;
Msg.Subject := QryMainSubject.AsString;
Msg.ContentType := 'multipart/alternative';
TxtPart := TIdText.Create(Msg.MessageParts);
TxtPart.ContentType := 'text/plain';
TxtPart := TIdText.Create(Msg.MessageParts);
TxtPart.ContentType := 'multipart/related; type="text/html"';

HtmPart := TIdText.Create(Msg.MessageParts, nil);
HtmPart.ContentType := 'text/html';
HtmPart.Body.Add('<html>');
HtmPart.Body.Add('<head>');
HtmPart.Body.Add('</head>');
HtmPart.Body.Add('<body>');
HtmPart.Body.Add(sHBody);
HtmPart.Body.Add('</body>');
HtmPart.Body.Add('</html>');
HtmPart.ParentPart := 1;
for i:=0 to AtchList.Count-1 do begin
BmpPart := TIdAttachmentFile.Create(Msg.MessageParts, pchar(AtchList[i]));
BmpPart.ContentType := 'image/jpeg';
BmpPart.ContentDisposition := 'inline';
BmpPart.ContentID := 'ImgID'+ IntToStr(i);
BmpPart.ParentPart := 1;
end;

Msg.ContentType := 'multipart/mixed';
QryDetailA.First;
while not QryDetailA.Eof do begin
AtchFile := UniServerModule.LocalCachePath +QryDetailAAtchFileName.AsString;
QryDetailAAtchFileData.SaveToFile(PChar(AtchFile));
TIdAttachmentFile.Create(Msg.MessageParts, AtchFile);
QryDetailA.Next;
end;
IdSMTP := TIdSMTP.Create(nil);
with UniMainModule do begin
idSMTP.Username := QryFirmSmtpUser.AsString;
idSMTP.Password := QryFirmSmtpPw.AsString;
idSMTP.Host := QryFirmSmtpHost.AsString;
idSMTP.Port := QryFirmSmtpPort.AsInteger;
end;
try
idSMTP.Connect();
try
idSMTP.Send(Msg);
sSql:= 'UPDATE Email SET Folder = 1, IsSent = 1, SentDate = GETDATE() WHERE (EmailId=0';
sSql:= sSql +QryMainMainId.AsString +')';
UniMainModule.Conn.Execute(Pchar(sSql));
ShowMessage('Message Sent');
except
on E: Exception do ShowMessage('Failed: ' + E.Message);
end;
finally
if IdSMTP.Connected then idSMTP.Disconnect();
Msg.Free;
IdSMTP.Free;
AtchList.Clear;
AtchList.Free;
end;
end;

end.

TestEMails.rar

TestRetriveMails.rar

merhabalar,

süper bir kod örneği,

bir kısmını çalıştırdım, dosya ekleyip gönderiyorum ancak mail gövdesine metin ekleyemedim.

html sayfayı ekleyemiyorum, 

ProcessHtml(sHBody, AtchList); kısmını yapamadım,

sizin örnekleri de indiremedim.

yardımcı olursanız sevinirim.

Mehmet

mdagli2003@gmail.com

 

 

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...