Sending email through Delphi - delphi

I have never worked with Delphi (my girlfriend have some experience), but there is a small tool that I want to make and I think it should be made on Delphi. After hours of searching and testing we found only this guide (http://delphi.about.com/od/indy/a/email-send-indy.htm) which doesn't work, it gives a huge error when pressing the Send email button.
I am trying to make a tool that will be distributed with my game and will allow the user to send me an email (to my Gmail) in case of a problem or for feedback. He will enter his email, attach a screenshot and fill in a comment box, doesn't need to have something else. Any help will be highly appreciated as I am stuck, thank you.

Here's a simple routine to send an email. I guess you can modify it to fit your needs:
procedure SendImage(const Comment, AImage: String);
var
SMTP: TIdSMTP;
Msg: TIdMessage;
begin
if not FileExists(AImage) then
Exit;
Msg := TIdMessage.Create(nil);
try
Msg.From.Address := 'xxxx#gmail.com';
Msg.Recipients.EMailAddresses := 'xxxx#gmail.com';
Msg.Body.Text := Comment;
TIdAttachmentFile.Create(Msg.MessageParts, AImage);
Msg.Subject := AImage;
SMTP := TIdSMTP.Create(nil);
try
SMTP.Host := 'smtp.gmail.com';
SMTP.Port := 25;
SMTP.AuthType := satDefault;
SMTP.Username := 'xxxx#gmail.com';
SMTP.Password := '##$%';
SMTP.Connect;
SMTP.Send(Msg);
finally
SMTP.Free;
end;
finally
Msg.Free;
end;
end;
PS: Note that you have to replace xxxx#gmail.com with your own email address, and not the user's. You could include their email address in the body of the crash report.

IMO, email is not going to work 100% of the time. You'll be lucky to get 80%. If you use your SMTP, firewalls and ISPs must permit it. If you use their existing email client, you rely on proper configuration. A typical scenario is that they use Gmail or Yahoo, and then you try to send something via "imap email already on system" and the user gets confronted with an old copy of Outlook Express or Windows Mail that they didn't even know they had, but it's "registered" with windows as the default email handler. This gets ugly.
I recommend sending via HTTP to an app on your web page. A PHP script that records the info and image into a MySQL database. Actually, I recommend using a bug tracking database like Mantis or FogBugz (from our patron!). I'd check them out, and then if you like what they offer, it's fairly straightforward to submit reports via HTTP post (or email, etc.).

Related

Sending email via GMail with app specific password

I maintain and develop a program that (amongst other things) sends emails via GMail.
Until now, there have been no problems with sending emails, but a few days ago this functionality ceased to work with a message 'Bad credentials'. I looked through the help of GMail and found this explanation/warning/what-have-you:
To help keep your account secure, from May 30, 2022, ​​Google no longer supports the use of third-party apps or devices which ask you to sign in to your Google Account using only your username and password.
The solution is to use the 'app specific' password.
I looked at this question that states:
My most recent try was to create an 'app specific' password on Gmail
But the attached code doesn't actually show how the password is sent.
Reading the question and its answers, I made some changes to my program:
Port := 995
UseTLS := utUseImplicitTLS
SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2]
After these changes, in an attempt to send a test mail (still no app specific password), I get the response
Reply code is not valid: +OK
which might mean that my program fails, as it doesn't send the app specific password.
What I want to know is: how to send that password?
Below is my code that executes as a thread, hence all components are defined in code:
email:= TIdMessage.Create (nil);
try
email.LoadFromFile (FFileName);
email.OnInitializeISO:= DoInitializeISO;
// DeleteFile (FFileName);
smtp:= TIdSMTP.Create (nil);
try
smtp.OnFailedRecipient:= FailedRecipient;
ssl:= TIdSSLIOHandlerSocketOpenSSL.Create (smtp);
ssl.SSLOptions.SSLVersions:= [sslvTLSv1];
smtp.OnStatus := DoStatus;
smtp.IOHandler:= ssl;
smtp.Host:= FHost;
smtp.Password:= FPassword; // now app passord
smtp.Username:= FUsername;
smtp.UseTLS:= utUseExplicitTLS;
smtp.Port:= 587;
smtp.Connect;
try
smtp.Send (email);
finally
smtp.Disconnect;
end;
finally
ssl.free;
smtp.Free;
end;
finally
email.Free;
end;
An application-specific password is simply a password that Gmail generates for you, and then you use it instead of your normal password (ie, in the TIdSMTP.Password property). This is explained in Gmail's documentation:
Sign in with App Passwords
You can just replace the password with the apps password. Assuming your code id similar to that below. Just remember you need to have 2fa enabled in order to create an apps password.
smtp.OnStatus := DoStatus;
smtp.IOHandler:= ssl;
smtp.Host:= FHost;
smtp.Password:= AppsPassword; // Password from Apps Password
smtp.Username:= FUsername;
smtp.UseTLS:= utUseExplicitTLS;
smtp.Port:= 587;
Another option would be to use Xoauth2.

Problems with email sent with Indy and ContentType = 'multipart/mixed'

I use the code that follows to send an email from a Delphi application using Indy.
I just left the core part of my routine:
MailMessage.From.Name:= UserName;
MailMessage.Encoding := meDefault;
MailMessage.Subject := MessageObject;
with TIdText.Create(MailMessage.MessageParts, nil) do begin
ContentType := 'multipart/alternative';
end;
with TIdText.Create(MailMessage.MessageParts, nil) do
begin
Body.Text:= MessageText; // MessageText could be eithr HTML or TEXT
ContentType := 'text/html';
end;
// recipients lists are populated
PrepareToList;
PrepareccList;
PrepareBccList;
// attachments are added to the MailMessage
AddAttachments;
MailMessage.ContentType := 'multipart/mixed';
//usage of TIdSMTP to send mail
SMTP.Connect;
SMTP.Send(MailMessage);
The code above somehow works
with most SMTP servers, the message recieved in Outlook looks like this:
...but when i user a specific "problematic" SMTP server, I see:
The first case is ok, the second is odd.
The strange thing is that when using a specific SMTP server, I reproduce this problem, with all the others it is fine.
Could you please give me soem hint to further understand what goes on?

Outlook automation with Delphi - Queue

I currently have the following code:
while not (sqlMailMergeData.Eof) do
begin
if sqlMailMergeData.FieldByName('Email').AsString <> '' then
begin
Inc(Count);
{Connect to Outlook}
MailItem := OpOutlook1.CreateMailItem;
MailItem.MsgTo := sqlMailMergeData.FieldByName('Email').AsString;
MailItem.Body := Form48.Memo1.Text;
MailItem.Subject := Form48.Edit3.Text;
MailItem.Send;
end;
Form34.sqlMailMergeData.next;
end;
However Outlook prompts you to allow ever email with a delay of 5 seconds. Sending after the loop overwrite the same MailItem.
MailItem.Save;
Saves all the items to draft without prompting. This is not a bad solution and could be an extra feature but requires more user input to move the items to outbox.
Is there a function to send each mail item to the outbox? or should I consider creating a string of all the email address e.g.
MailItem.MsgTo := "example#email.com; example2#email.com"
Thanks
When working with outlook, you might consider using outlook redemption1, this way you can bypass the security prompt and send the mail directly from your code.
Then your only option is to do what Redemption (I am its author) is doing under the hood - use Extended MAPI.
This is the code which works fine for me:
Outlook := CreateOleObject ('Outlook.Application');
// Repet the code below for each mail:
OutlookMail := Outlook.CreateItem (olMailItem); // olMailItem = 0;
OutlookMail.Recipients.Add ('example#email.com').Resolve;
OutlookMail.Recipients.Add ('example2#email.com').Resolve;
OutlookMail.Subject := Form48.Edit3.Text;
OutlookMail.Body := Form48.Memo1.Text;
OutlookMail.BodyFormat := olFormatHTML;
// OutlookMail.SendUsingAccount := OutlookAccount; // If you need to select the acount
OutlookMail.Send;

Check unread messages with Indy

I'm doing just for fun an unread messages checker application in Delphi. I'm using Indy 10. I can connect with Gmail and can retrieve all the messages but I'm facing a problem here: I cannot tell if a message is already read or not. There is a flag property in the TidMessage component that should tell me if the message has been read.
The code looks like this:
procedure TForm1.btTestConnectionClick(Sender: TObject);
var
i: Integer;
count: Integer;
flag: TIdMessageFlags;
begin
if (pop3Test.Connected) then begin
pop3Test.Disconnect;
end;
pop3Test.Username := edAccount.Text;
pop3Test.Password := edPassword.Text;
pop3Test.Host := HOST;
pop3Test.AuthType := patUserPass;
pop3Test.Port := PORT;
pop3Test.Connect;
Count := 0;
for i := pop3Test.CheckMessages downto 1 do begin
pop3Test.Retrieve(i, IdMessage1);
if (mfSeen in IdMessage1.Flags) then begin
Count := Count + 1;
end;
end;
ShowMessage(IntToStr(Count));
pop3Test.Disconnect;
end;
In the test mailbox there is one unread message but all the retrieved messages have the flags enum property empty so the result is always 0. Am I doing something wrong? Is it a problem of Indy/Gmail compatibility?
Thanks.
EDIT: I'm definitely doing something wrong as testing with a Hotmail account shows the same empty-flags property problem.
the POP3 protocol does not support Message state information on the server like read, replied to, or deleted . try using IMAP for Gmail instead.
The best (and quickest) way to find this answer would be to search the Indy sourcecode for "mfSeen" You should find it only utilized in idIMAP* units. RRUZ is correct - POP3 doesn't offer this inherent ability. In POP3 you need to track this on the client side. This flag was added to IdMessage for IMAP purposes, and not necessarily for POP3.
TIdMessageFlags should likely have been named TIdIMAPMessageFlags

Send Email in HTML Format

At the moment we are using MAPI to send a plain text email from our application. We specify the dialog flag when the user invokes this function, so that the email will appear in their email client and they can then modify it and send it.
We would like to embelish the email and send it in an HTML format.
According to this link MSDN link MAPI is not sutiable for this http://support.microsoft.com/kb/268440
I have seen an article on ExpertsExchange that say you can use MAPI to do it but I can't get the example to work with Outlook (not tried anyother client yet)
procedure ShowMailDlg(ToName,Address,HTMLMessage: string);
var
li: integer;
lMessage: TMapiMessage;
lRecipArray: array of TMapiRecipDesc;
lREs: DWord;
begin
SetLength(lRecipArray,1);
lRecipArray[0].ulRecipClass:=MAPI_TO;
lRecipArray[0].lpszName:=pChar(ToName);
lRecipArray[0].lpszAddress:=pChar(Address);
lMessage.ulReserved:=0;
lMessage.lpszSubject:=nil;
lMessage.lpszNoteText:=pChar(HTMLMessage);
lMessage.lpszMessageType:= nil;//pChar('HTML');
lMessage.lpszDateReceived:=nil;
lMessage.lpszConversationID:=nil;
lMessage.flFlags:=0;
lMessage.lpOriginator:=nil;
lMessage.nRecipCount:=length(lRecipArray);
lMessage.lpRecips:=PMapiRecipDesc(lRecipArray);
lMessage.nFileCount:=0;
lMessage.lpFiles:=PMapiFileDesc(nil);
lRes:=MapiSendMail(0, 0 , lMessage,MAPI_DIALOG, 0);
end;
Anyone have any ideas how I can do this. I could probably automate Outlook but I would like to keep it fairly independant of email client (hence MAPI)
Thanks
Update: thanks to everyone for the suggestions. The feature is question is not that heavily used, so asking the user to configure SMTP details is not really an option. I think we will just stick to the plain text email.
Thanks
MAPI doesn't support HTML formatted messages. From Microsoft : "Extended Messaging Application Programming Interface (MAPI) should not be used to generate HTML-formatted messages. As an alternative, consider using the Microsoft Outlook Object Model, CDONTS, CDOSYS, CDOEX, or a third-party SMTP control."
I would echo the comments about sending via Indy. I published a unit that works to send HTML messsages with Indy very simply here or feel free to write your own. If you really want to make the messages editable, try a combination of WPTools and Indy. WPTools has good support for HTML markup and then you can send the resulting message via Indy.
I don't have any experience with Synapse so I can't say how easy/hard it is with that project.
If you only have to serve Outlook clients you could try accessing Outlook by OLE:
procedure SendMail(const aRecipient, aSubject, aNote, aFile: string; Silent, HTML: boolean);
const
olMailItem = 0;
var
ii: integer;
MyOutlook, MyMail: variant;
begin
//*** Send something via OLE/Outlook...
//*** Outlook- und Mail-Objekt erstellen...
MyOutlook := CreateOLEObject('Outlook.Application');
MyMail := MyOutlook.CreateItem(olMailItem);
//*** create a mail message...
MyMail.To := aRecipient;
MyMail.Subject := aSubject;
if aNote <> '' then begin
if HTML then
MyMail.HTMLBody := aNote
else begin
MyMail.Body := aNote;
end;
end;
//*** Add Attachment...
if aFile <> '' then begin
MyMail.Attachments.Add(aFile);
end;
if Silent then
MyMail.Send
else
MyMail.Display;
MyOutlook := UnAssigned;
end;
This is also possible using the Synapse library. A specific example is available from the howto page titled "About MIME and its MIME Parts". I personally have used this technique in several programs to send HTML email.
Unfortunately, this doesn't work over MAPI, you will need to get the users SMTP or IMAP information and handle that communication yourself (the Synapse library has routines to do just that).
If you decide to download Synapse, I strongly suggest getting the latest version from the subversion repository. The update available there includes support for Delphi 2009.
For Delphi emailing I would recommend SakEmail
http://groups.yahoo.com/group/sakemail/
If you're using a version of delphi higher then 7,
you should add the version definition to the .inc file.
that's supplied with SakEmail, else it will fall back to
Delphi4 compatibility mode. After patching the inc file it seems
fine with Delphi 2005.
also, it seems HTML over MAPI works in Thunderbird, but no other client.
There is an undocumented feature of MAPISendMail for including an HTML body:
set lpszNoteText to nil (or a pointer to an empty string)
add an HTML attachment
MAPI will use the html attachment as the body of the e-mail (and not include the attachment).
You can use SMTP with Indy:
HTML Messages
New HTML Message Builder class (Indy 10)
You should consider using an SMTP component, Indy for example, and adding the user doing the sending to the CC or BCC field of the message. This largely satisfies the need to have such sent messages appear in the user's own mail client, which is the primary advantage of MAPI. The user may even set up a separate account specifically for receiving such copies.
Doing it this way allows you to completely customize every detail related to sending mail (MHTML being one such example), including caching all mail and doing the sending in a separate thread, or at a different time, and so on. Also, this method is more client-agnostic than even MAPI; for example, this still works even if the user is using web-based email such as Gmail.

Resources