Sending mail with INDY/DELPHI , modify values without restrictions - delphi

I'm sending E Mails with INDY 10 components with the following code :
try
MyNewIndyMessage.From.Address := edFrom.Text;
MyNewIndyMessage.Recipients.EMailAddresses := edTo.Text;
MyNewIndyMessage.CCList.EMailAddresses := edCC.Text;
MyNewIndyMessage.BCCList.EMailAddresses := edBCC.Text;
MyNewIndyMessage.Subject := edSubject.Text;
MyNewIndyMessage.Body := edContent.Lines;
MyIndySMTP.Send(MyNewIndyMessage);
finally
MyIndySMTP.Disconnect;
end;
Indy smtp requests me to enter a valid organisation in the Message.from.address like "myname#companyX.com" , I wouöld like to enter here and arbitray string like "This mail is urgent to read".
Can I bypass such check done in my INDY SMTP components ?

According to the Internet Message Format specification (RFC 2822), the From field must contain a valid mailbox, which normally is (section 3.4):
Normally, a mailbox is comprised of two parts: (1)
an optional display name that indicates the name of the recipient
(which could be a person or a system) that could be displayed to the
user of a mail application, and (2) an addr-spec address enclosed in
angle brackets ("<" and ">"). There is also an alternate simple form
of a mailbox where the addr-spec address appears alone, without the
recipient's name or the angle brackets.
An example of this may be like this:
John Doe <john.doe#example.com>
As implied, mail clients usually display the (optional) name attribute if present, and the address itself if a name is not present.
In INDY terms, the TIdEMailAddressItem have three properties, which are always in sync:
Address is the address-spec part of the mailbox, for example: john.doe#example.com
Name is the name part of the mailbox, for example: John Doe
Text have both parts, for example: John Doe <john.doe#example.com>
You can change one of that and the others will reflect the same changes.
So, you can do what you want by setting the Text property directly, like this:
MyNewIndyMessage.From.Text := 'This mail is urgent to read <myname#companyX.com>';
Or you may want to set each one separately:
MyNewIndyMessage.From.Address := 'myname#companyX.com';
MyNewIndyMessage.From.Name := 'This mail is urgent to read';
All this said, you may want to use that name as the subject (along with some more info), and not really as the name, but that's up to you.

Related

How to extract all email address from an Indy TIdMessage object?

Using Indy, how can I extract all email addresses that are present in the To, Cc and Bcc fields of a TIdMessage? As these fields can contain more than one address, I must parse them, but I didn't find any ready-made function for that (maybe I've missed it?).
You obviously did not read the
TIdMessage documentation:
TIdMessage.BccList
TIdMessage.CCList
TIdMessage.Recipients
Identifies the recipients of a message.
property Recipients: TIdEmailAddressList;
Description
Recipients is a TIdEMailAddressList property used to store TIdEmailAddressItem values that identify the recipients of the message. Use CCList for recipients to receive a Carbon Copy of the message. Use BCCList for recipients to receive a Blind Carbon Copy of the message.
All of these properties give you a TIdEmailAddressList that you can harvest for addresses.
This is the second item in a google search for Indy TIdMessage.
For example:
function GetEmailAddresses(const Email: TIdMessage): TStringList;
var
Item: TIdEmailAddressItem;
begin
Result := TStringList.Create;
for Item in Email.Recipients do Result.Add(Item.Address);
for Item in Email.CcList do Result.Add(Item.Address);
for Item in Email.BccList do Result.Add(Item.Address);
end;
Note that the Indy documentation uses the with keyword a lot.
Although convenient, using with is a very bad idea and I recommend you avoid it at all costs.

How to save an email attachment to file

I would to save an email attachment to a file using a TIdImap4 object of Indy Ver.10.
I get the UID of the email, then I use this code:
lMsg := TIdMessage.Create(Self);
lImap.UIDRetrieveStructure(lUid, lMsg);
lMsg.MessageParts.CountParts;
if lMsg.MessageParts.AttachmentCount > 0 then
for lJ := 0 to lMsg.MessageParts.Count - 1 do
if (lMsg.MessageParts[lJ] is TIdAttachment) and
SameText(lMsg.MessageParts[lJ].Name, 'MyAttachment') then
lImap.UidRetrievePartToFile(lUid, lJ, lDimAllegato, lFileName, Trim(lMsg.MessageParts[lJ].ContentTransfer))
This worked until lMsg.MessageParts[lJ].ContentType = 'Text/Plain' and
lMsg.MessageParts[lJ].ContentTransfer = '7bit', now UidRetrievePartToFile() returns False and no file is created. I suppose because
lMsg.MessageParts[lJ].ContentType = 'application/octet-stream' and
lMsg.MessageParts[lJ].ContentTransfer = 'base64'.
I'm not skilled on this topic, what I need to change in code in order to save this type of attachment?
I also tried with: TIdAttachment(lMsg.MessageParts[lJ]).SaveToFile(lFileName)
and similar, but the file created was always empty.
Using UIDRetrieveStructure() with a TIdMessage is going to fill the TIdMessage.MessageParts with a lot of TIdttachment objects, never any TIdText objects, and not all of the objects are going to represent actual attachments. You are using the TIdAttachment indexes as the APartNum parameter of UIDRetrievePartToFile(), which might not be accurate.
And you can't use TIdAttachment.SaveToFile() when using UIDRetreiveStructure(), because no actual data has been downloaded, only the structure of the email, which then allows you to download the data for the specific elements you want.
I suggest you use the other overloaded version of UIDRetrieveStructure() that fills a TIdImapMessageParts instead. Amongst other things, TIdImapMessagePart gives you an exact ImapPartNumber that you can then give to UIDRetrievePartToFile() (as well as the ContentTransferEncoding):
lParts := TIdImapMessageParts.Create(nil);
try
lImap.UIDRetrieveStructure(lUid, lParts);
for lJ := 0 to lParts.Count - 1 do
begin
if (lParts[lJ] is the desired attachment) then
begin
lImap.UidRetrievePartToFile(lUid, lParts[lJ].ImapPartNumber, lDimAllegato, lFileName, lParts[lJ].ContentTransferEncoding);
end;
end;
finally
lParts.Free;
end;

How can I set a message unread?? with delphi 7 and imap from indy10

How can I set a email message unread??
Here I read the emails from inbox in gmail
When I read gmail, it flag like read, so I would like to flag like unread again.
TheImap.GetUID(i+1, TheUID);
TheImap.UIDRetrieveFlags(TheUID, TheFlags);
TheImap.UIDRetrieveHeader(TheUID, TheMsg);
TheImap.UIDRetrieveText(TheUID, lacadena);
if mfSeen in TheFlags then begin
TheImap.StoreFlags(TheUID, sdReplace, TheMsg.Flags - [mfSeen] );
You are trying to pass a UID string where a MsgNum integer is expected. You need to use UIDStoreFlags() instead of StoreFlags():
TheImap.UIDStoreFlags(TheUID, sdReplace, TheFlags - [mfSeen]);

Datasnap & Fmx Mobile App How to send a dataset containing a blob field

I had a multi tier project in which i would collect data from a microsoft sql 2005 through a FDStoredProc with a function and the function would return a dataset to the client. When the server assigns the dataset to the result of the function and the function tries to send it to the client i get this error. Project etctec.exe raised exception class TDBXError with message 'TDBXTypes.BLOB value type cannot be accessed as TDBXTypes.Bytes value type'.
In another project i used the StoredProc of a different database with TFDStoredProc in exactly the same way and it works fine. Any ideas what would raise this error?
This is what i do in the server.
function TServerMethods1.getCategories(): TDataSet;
begin
FDStoredProc1.ParamByName('#val1').AsInteger:= 1;
FDStoredProc1.ParamByName('#val2').AsInteger:= 0;
FDStoredProc1.ParamByName('#val3').AsInteger:= 1;
FDStoredProc1.ParamByName('#val4').AsInteger:= 1;
FDStoredProc1.Open();
result:= FDStoredProc1;
end;
and the client calls it like this...
dataset:=ClientModule1.ServerMethods1Client.getCategories();
Problem comes from some fields that are of type NVARCHAR(max), anyone knows a workaround to this error without changing the field type?
I tried changing the dataset's field type to a string or something with no success. The only thing i can temporarily do is get these fields separately, put them in a stringlist or something like that and pass it to the client.
I think you should use some of similar methods below:
http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.CreateBlobStream
http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.GetBlobFieldData
You should define you field as a blob field and then put data in/out with the functions described in the links.
Here is also example how to copy data:
http://docwiki.embarcadero.com/Libraries/XE4/en/Data.DB.TDataSet.CreateBlobStream

Get System minimum password length and complexity

In local security policy (PC-Control panel-Administration-local security policy) there is a parameter "Minimum length of the password" and a parameter "Password must meet complexity requirements" (true/false). How can I read them in Delphi (for WinXpSp3-Win2003-Vista-Win7-Win2008(+r2))?
I'm looking for something like:
Function DetectSystemMinPassLength:integer;
begin
//?
end;
Function DetectSystemPassComplexity:boolean;
begin
//?
end;
Additional question:
Does there exist in Delphi (or WinApi) function which can check if a given password conforms to system policies (or set)?
For example:
Function MyCheckPassComplexity (Password:string):boolean;
begin
// ???
end;
use
MyCheckPassComplexity (' 12345 '); //result False
MyCheckPassComplexity (' MyCoolPassword9999 '); //result True
Usually to read a local or group policy setting you must use the Group Policy Settings Reference for Windows and Windows Server which basically is a set of excel files which contains the windows registry keys where is stored such info. unfortunately in this case if you check such reference for these Account policies (Enforce password history,
Maximum password age, Minimum password age, Minimum password length) you will find this message:
Password Policy security settings are not registry keys.
Exist a set of WMI classes in the root\RSOP\Computer namespace like RSOP_SecuritySettingBoolean, RSOP_SecuritySettingNumeric , RSOP_SecuritySettings to access the an account policy but these classes only works (I mean retrieve information) on systems which is are in a domain, but it does not work in a workgroup.
For the moment I think which you best option is export the local policies to a ini file using this command (and then parse the result using a TIniFile class)
secedit.exe /export /cfg C:\Output\Policy.Ini
This command will create a file like this
[Unicode]
Unicode=yes
[System Access]
MinimumPasswordAge = 0
MaximumPasswordAge = 42
MinimumPasswordLength = 0
PasswordComplexity = 0
PasswordHistorySize = 0
About your second question to validate a password you can use the NetValidatePasswordPolicy WinAPI function.

Resources