NetTalk Email
Introduction
Almost all programs can benefit from Sending and/or Receiving emails.
NetTalk makes it easy to add simple, or sophisticated, email handling
abilities directly into your application.
Emails are sent using the
SMTP protocol.
Emails are received using either the POP3 or IMAP
protocol.
Upgrading
In NetTalk 10 (specifically 10.22 and later) some of the properties changed
from STRING values to STRINGTHEORY objects. Because assigning a value to an
object using the = sign causes a GPF, the names of the properties have
changed. This means that if you have used the old properties in your embed
code then you will get a compile error.
If you get a compile error in
your code then you can replace the old property name, and syntax, with the
new property name and syntax.
These changes affect Email Sending
(SMTP), Email Receiving (POP3 and IMAP) classes.
Old Syntax | New Syntax |
x = email.WholeMessageLen | x =
email.WholeMessageST.Length() |
s = email.WholeMessage | s =
email.WholeMessageST.GetValue() |
x = email.MessageTextLen | x = email.MessageTextST.Length() |
s = email.MessageText | s = email.MessageTextST.GetValue() |
email.MessageText = s | email.MessageTextST.SetValue(clip(s)) |
x = email.MessageHTMLLen | x = email.MessageHTMLST.Length() |
s = email.MessageHTML | s = email.MessageHTMLST.GetValue() |
email.MessageHTML = s | email.MessageHtmlST.SetValue(clip(s)) |
if Imap.wholeMessageLen | if Imap.wholeMessageST.Length() |
x = email.BufferLen | x =
email.BufferST.Length() |
s = email.Buffer | s =
email.BufferST.GetValue() |
The prototype for the following methods have changed;
MethodName | Change |
EmbedImages | First parameter
has changed from a *string to a
StringTheory object. |
The following methods are no longer required, and if you have called them in
your embed code then you can just remove the call;
MethodName |
SetRequiredMessageSize |
JumpStart
Sending Emails
The example in
\clarion\examples\NetTalk\Email\Demo\ABC is the best email
example. And you can import various dictionary tables and procedures
directly from there to speed things along. References to "the example"
in the text below are referring to this example. A Legacy version of
this example is in
\clarion\examples\NetTalk\Email\Demo\LegacyIn order to be able to send emails from your application there are
really only a few basic things to do;
- Allow the user to enter server connection settings somewhere so
that your program knows which server to send to.
- Optionally, create a EmailLog table in your dictionary, and add
a browse on this to your app.
- Create a SendEmail procedure which you can call from anywhere in
your code.
- Add a call to SendEmail in all the various places where you wish
to send emails.
Server Connection Settings
A number of settings are used when connecting to a server. These settings can vary from one installation to the next
so it's important to allow the user to capture these. Once set (on one workstation) the settings are usually valid for
all the workstations so (assuming the settings are visible to all machines) no per-workstation setup is required.
You could add these settings to your existing shared settings table or you could create a new table.
The settings are as follows:
- EmailServer (String 255)
This is the URL of the server.
It's sometimes an IP address (eg 192.168.1.1) or a DNS name (eg
mail.capesoft.com)
- EmailPort (Long) (A long.
The default value should be 25.
Values of 587, 990 and 465 are also commonly used.
- AlwaysSSL (Long).
A boolean value (0 or 1) this is set to 1
if the connection to the server is always over TLS
- StartTLS (Long)
A boolean value (0 or 1) this is set to 1 if
the connection starts normally but then a STARTTLS command switches
it to TLS.
- SSLMethod (Long)
The TLS version to use when connecting to
the server. The default is TLS 1.2, 1.1 or 1.0 (in that order).
- UserName (String 255)
The user name for the user on the
server.
- Password (String 255)
The password for this user when
connecting to the server
- FromAddress (String 255)
The default FROM address of the "person"
sending the email. All emails must have a valid FROM address (ie the
server must recognize the FROM address) or the chance of the email
being successful is very small.
Once you have the fields in your table you should give the user
some way to change these settings. They will need to be different
with each site you install, so the user will need to have access to
them.
Tip: On one of our internet
machines we run a mail server. In our shipping programs we default
all the above settings to that (internet) mail server. This
increases the chances of the email sending "just working"
immediately after the program is installed. The customer can change
the settings later if they like. Of course if they've blocked the
outgoing port in their firewall then they won't be able to send via
our server, but then they will have their own internal server they
can route the mail through.
EmailLog Table
Keeping a record of outgoing emails is very useful. Exposing this
record to the customer adds value to your program and also allows
them (or you) to audit what emails were sent, and when.
While
you can store any fields you like in this table, the following are
recommended;
- Guid (String 16)
- User (String 255)
- Date (Long / Date)
- Time (Long / Time)
- SendDate (Long / Date)
- SendTime (Long / Time)
- ToEmail (String 255)
- FromEmail (String 255)
- Subject (String 255)
- CC (String 255)
- BCC (String 255)
- Attachment (String 1024)
- EmbedList (String 1024)
- MessageText (MEMO 64000)
- MessageHTML (MEMO 64000)
- Status (Long)
Global Variables
When logging outgoing emails it's useful to know the current user's Name and Email Address.
(ie the name and address of the user currently using the program.)
There are many systems for managing users, so the easiest way to
support this is to add two global variables to your program. These
can be set when a user logs in, (you will need to do that in your
embed code) and then used in the
SendEmail
procedure when a mail is
sent.
The global variable names are
- Glo:UserEmail (String 255)
- Glo:UserName (String 255)
You can change these names if you need to - then just change where
they are used in the
SendEmail procedure.
UpdateEmailSettings Procedure
The example contains a sample procedure which just edits a single
record in a table. Of course you may have added the fields to an
existing table, in which case just use your existing form to set the
settings.
BrowseEmailLog Procedure
An example of this procedure is in the example. This procedure is
optional. It allows users to see what emails have been sent, and if
desired, resend an email that did not get through. This procedure is
a very standard browse on the table - there are no special NetTalk
extensions here.
The only bit of hand-code in the
procedure revolves around the Resend button.
SendEmail Procedure
The SendEmail procedure is a normal procedure in your app tree, so
you have a lot of control over what the window looks like, and how
it works. If you are logging emails then this is a great procedure
to add the logging code to.
The SendEmail procedure has the
following prototype;
(EmailParametersGroup
pEmail),Long,Proc
The parameters are set to;
(EmailParametersGroup pEmail)
the
NetTalk Send Email control template has been added to the window.
Note the template settings for this, as this is where you use a
combination of the email server settings, and the parameters to
construct the email. See the example for some ideas.
The example
contains an interface which makes debugging email problems easier.
It allows you to see the conversation between the program and the
email server as it occurs. The log of the most recent conversation
is also written to a text file for you. Plus of course each outgoing
email is logged to the EmailLog table.
You can of course edit
this procedure to make it work, or look, different so that it better
matches your application.
Calling the SendEmail Procedure
The SendEmail procedure can be acalled from any other procedure. It might be a button, or a menu item,
or it might happen in source code when some event occurs. To call SendEmail follow these steps:
- Create a local variable in the procedure;
parms group(EmailParametersGroup).
- Where you want to send the email, prime the components of the
parms parameter
clear(parms)
parms.pEmailTo = 'bruce@capesoft.com'
parms.pEmailFrom = glo:UserEmail
parms.pEmailSubject = 'Great
Release'
parms.pEmailCC = ''
parms.pEmailBCC = ''
parms.pEmailFileList = ''
parms.pEmailEmbedList = ''
parms.pEmailMessageTextST.SetValue('Well done on a great release')
parms.pEmailMessageHTMLST.SetValue('<html>...</html>')
- Call the SendEmail procedure. You can do this on another thread;
START(SendEmail,25000,parms)
or on
the same thread (in which case you get a returned value;
result = SendEmail(parms)
Receiving Emails
IMAP
Non-ASCII Characters
For English speaking users, who exclusively use the Roman alphabet from
A to Z there is no issue here, and this section in the documentation can
be skipped.
For non-English speaking users though, you may need
to deal with non-roman characters. You will have some choices in how you
do that though, and so those choices need to be communicated to the
class so that it knows what you are doing. The default approach though
is the one most likely to be used by your program, so it is probable
that you will not need to do anything yourself.
A number of the class
properties could be subject to these foreign characters. These include
any email address list (
From,
To,
CC,
BCC), the
Subject
and of course
the
MessageText and
MessageHTML. It is assumed that whichever approach
you take to handling foreign characters, this approach is consistent
across all these properties.
The two primary approaches to
encoding non-ASCII text are to either use Unicode, or codepages (aka
charsets). Since Clarion (up to version 10) cannot display, or get user
entry, in Unicode, most programs would use the codepage approach.
Codepages (Charsets)
This is the default approach for non-ASCII characters. The codepage
property will default to the setting (
system{prop:charset})
used in your program, so it is likely there is nothing you will need
to do. If your system charset is set then the class will assume that
all outgoing properties are in that charset, and all incoming
properties need to be converted to that charset.
You are also
able to set the
codepage property
yourself to any
st:CP_ value, as listed
in
StringTheory.Inc.
The
CodePage property will only be used if
the
encoding property is not set to
either
st:EncodeUtf8 or
st:EncodeUtf16 (see
Unicode below).
Unicode
If your email values are already formatted in Unicode then you MUST
set the encoding property before
calling the SendEmail method. It should
be set to either st:EncodeUtf8 or
st:EncodeUtf16 (depending on how you
have formatted your strings.)
SendEmail Control Template
The SendEmail Control Template lets you easily create your own SendEmail procedure. It places a lot of fields on the
window for you, but you can obviously remove the ones you do not want to see. In the Demo example all the fields,
except the actual Send button have been removed.
The Control
template also acts as the "Glue" between the incoming parameters, the
application-wide email settings, and the SendEmail object. The template
settings should be filled in carefully.
General Tab
Object Name
Defaults to ThisSendEmail. You can change this if you like.
Base Class
Defaults to NetEmailSend. You can change this to a derived class if you have written one.
Settings Tab
Server
Usually taken from your global setting or settings table.
Port
Usually taken from your global setting or settings table.
User
Usually taken from your global setting or settings table.
Password
Usually taken from your global setting or settings table.
Helo
Usually left blank, then the domain from the FROM address is used.
AlwaysTLS
Usually taken from your global setting or settings table.
StartTLS
Usually taken from your global setting or settings table.
CA Root File
Usually a fixed value,
'caroot.pem'.
The
caroot.pem file will be copied to the application folder for you and should be
distributed with your application.
To
Could be the field on the Window, if the field is there, else set it to
pEmail.pEmailTo.
From
Usually set to
loc:EmailFrom. This field is
calculated in code based on what the user entered, on the parameters, and the global setting.
CC
Could be the field on the Window, if the field is there, else set it to
pEmail.pEmailCC.
BCC
Could be the field on the Window, if the field is there, else set it to
pEmail.pEmailBCC.
Subject
Could be the field on the Window, if the field is there, else set it to
pEmail.pEmailSubject.
Attachments List
Could be the field on the Window, if the field is there, else set it to
pEmail.pEmailFileList.
Embeds List
Could be the field on the Window, if the field is there, else set it to
pEmail.pEmailEmbedList.
Text
Could be the field on the Window, if the field is there, else set it to
pEmail.pEmailMessageText.
HTML
Could be the field on the Window, if the field is there, else set it to
pEmail.pEmailMessageHTML.
Show Messages
If this is on the a
MESSAGE window is called when the email is sent (or if it fails to send.)
Change Cursor While Sending
If this is on then the cursor will change to a
Cursor:Wait while the email is being sent.
Suppress Error Messages
If this option is on then unexpected error messages will not appear in a
MESSAGE window.
EmailParametersGroup
A group structure has been defined to easily move multiple fields between procedures. Usually this
is used when calling the SendEmail procedure. You don't have to populate all the fields in the group,
the ones you don't need can be left blank.
Name | Type | Description |
pEmailFrom | String | The from address of the person
sending the email. |
pEmailTo | String | A semi-colon separated list of
email addresses that the email is going To. |
pEmailSubject | String | The subject line of the
email. |
pEmailCC | String | A semi-colon separated list of
email addresses who will receive a cc of the mail. |
pEmailBcc | String | A semi-colon separated list of
email addresses who will receive a bcc of the mail. |
pEmailFileList | String | A comma separated
list of files to attach to the email. |
pEmailEmbedList | String | A comma separated
list of images that have been embedded in the email. (If left blank
this will be constructed by the SendEmail object as long as the
images are accessible.) |
pEmailMessageText | String | The "text" contents of
the email itself. |
pEmailMessageHtml | String | the "html" contents of
the email itself. |
pEmailSettingsPath | String | not used |
pEmailTest | Long | not used |
pHelo | String | not used |
pSSL | Long | not used |
pStartTLS | Long | not used |
pSign | Long | Digitally
signs the email if the necessary certificate is installed. |
pHide | Long | Indicates to the Email Sending window
if it should be visible or not. |
Constructing HTML Emails
Text Version
Some mail readers, by design or user preference, do not display the HTML part of an email. So even if you
populate the MessageHTML property, you
should also populate the MessageText
property when creating an email. If the client does not display HTML
they will display the MessageText part.
HTML Version
Different mail clients use different HTML rendering engines to
display emails. Notably Outlook uses the Microsoft Word engine
(which is not as advanced as the engine used by IE.) Some clients
will remove any links to external CSS, and even CSS collected into a
<style> section.
For this reason the HTML used in emails
needs to be very simple, and very "old school". If you do send more
complex HTML then testing is definitely your friend.
There are
numerous posts on the internet regarding best practices in this
space - some recommended ones are;
Embedded Images
When
constructing the HTML it is often desirable to embed images in it.
This is usually done using the HTML
<img>
tag. For example;
<img src="http://www.capesoft.com/images/logo.png"
>This embeds a link to the image in the HTML. The
image itself is not included in the HTML. Rather the image is
fetched from the server when the user opens the email
[1]. Unfortunately many users
have images of this sort turned off in their email client, so the
user never fetches, and never sees, the image.
There is a way
though to embed the image in the HTML so that it is included in the
email itself, and no call to the web server is required. You need to
create an
<img> tag,
setting the source to a local resource. For example;
<img src="c:\images\logo.png" >or
<img src="logo.png" >If the HTML
is constructed in this way, then you need to make a call to the
ProcessHTMLForImages method;
thisEmail.ProcessHTMLForImages(rootfolder)The
Rootfolder
parameter allows you to specify a location on the disk. This
location will be used by any images which do not have a path set
(such as
<img src="logo.png" >)
This method should be called after the
MessageHTML property has been
set, and before the call to
Send.
[1] The use of external
images in an email message is often used my marketing folks to track
when an email was read. This has the side effect of validating email
addresses for spammers. For this reason most email clients are set
to not load external images by default. Since most users leave the
default as is, or even explicitly turn images off, this approach of
using external images has largely fallen out of favor.
Digitally Signing Emails
When you send an email to a person, you can digitally sign it. If you do
this, and the client email program the receiver is using supports
digital signatures, then they will be able to verify that you sent the
email, and the content of the email has been unaltered since you sent
it.
Note that a Digital Signature is different to the simple
Signature option that many email clients provide - the feature that adds
simple text to the end of your emails. That is a different thing, and
completely unrelated to Digital Signatures.
Digital Signatures
require that you acquire and install a special kind of certificate,
known as an Email Certificate, on the sending computer. This certificate
is specific to the FROM address that you will be using to send your
emails from. These certificates are widely available and are usually
free. For example
Comodo offers a free certificate, but
Googling offers many possible choices.
Once you have acquired
your certificate it needs to be imported into the Windows Certificate
Store on the sending computer. You can run the Certificate Manager by
running the
CertMgr.Msc program. Go to the
Personal / Certificates area,
right-click on the
Folder and
Select All Tasks / Import from the menu.
Follow the wizard to import the file. (Note that some web pages for
acquiring the certificate install the certificate into the store for you
automatically, so this step may not be needed.)
Certificates do
expire, typically after 12 months, so you will need to renew them every
year.
To digitally sign an email, when sending, set the property
OptionsSigned to one of
Net:NoSign (the default),
Net:Sign or
Net:TrySign. If set to
Net:Sign, and the certificate does not exist, then the mail will
not get sent. If it is set to Net:TrySign, and the certificate does not
exist, then the mail will be sent unsigned. For example;
net.OptionsSigned = Net:Sign
While there are other properties you can set at this point, related
to digital signatures, it is unlikely that you will want to change them
from their default values. These options, and default values are;
Property | Default Value |
OptionsSignedProtocol | application/x-pkcs7-signature |
OptionsSignedMicAlg | sha256 |
OptionsSigName | smime.p7s |
In some cases (if the client is unable to process a SHA-256 hash) it may
be necessary to change the
OptionsSignedMicAlg
property to 'sha1'. However this should only be done if problems
with old email clients is encountered.
The FROM address for the email is automatically used to identify the
certificate to use. If an appropriate certificate is not found, and
OptionsSigned is set to
Net:Sign, then
ErrorTrap will be called and the email will
not be sent. If
OptionsSigned is set to
Net:TrySign then the email will be sent
unsigned.
FAQ
- Gmail : Enable Less Secure Apps
- Secure Email Stopped Working
- Someone just tried to sign into
your Google Account....
- 550 Relaying Prohibited
- External Exchange Failure
- EML File
Gmail : Enable Less Secure Apps
Secure Email Stopped Working
My email program, which has been working for a long time, using an old build of NetTalk is now getting errors and is unable to send.
The error number was -69 which means the SSL Remote Certificate
Failed Verification.
If you are connecting to a server via SSL (specifically SSL v3)
then you may encounter this problem. SSLv3 was the default level for
SSL used for earlier versions of NetTalk. SSL v3 was however broken
in October of 2014, and was declared deprecated by the Internet
Engineering Task Force (IETF) in
RFC
7568 in June of 2015. As a consequence of the attacks in October
2014 many servers immediately moved to stop supporting SSLv3 and
this was accelerated by the RFC in June 2015.
The solution is
to change the connection your program uses from SSLv3 to TLS. If you
are on a recent NetTalk version (NetTalk7 or later) then make sure
you are on the latest build and this should be done for you
automatically. (The internal default changed from SSLv3 to TLS in
build 8.30 and 7.40)
If you are using an older NetTalk, or if
you have specifically set the SSLMethod property for a class (so it
is not just the default value) then you will need to set the
property manually. In your code add;
net.SSLMethod =
NET:SSLMethodTLSv1
If you are on NetTalk 8 or
later then use the
NET:SSLMethodTLS
equate as this covers all TLS versions, and defaults to the highest
level of security.
If you are using NetTalk 7 then you can
use
NET:SSLMethodTLSv1, NET:SSLMethodTLSv1_1
or
NET:SSLMethodTLSv1_2 equates.
NetTalk 6 and earlier does not support anything other than
NET:SSLMethodTLSv1.
Warning: It is probable that at some
point servers will turn off support for TLSv1 at which point
programs earlier than NT build 7.40 will cease working. An update to
NetTalk 8 (or later) is thus recommended to avoid problems when this
happens.
550 Relaying Prohibited
"I am getting 550 Relaying Prohibited Errors when trying to send email. What's going on?"
Relaying problems are all to do with your Email Server. Basically
it doesn't like who you are sending emails
From. There are a couple of
things you can do to try and resolve this:
- Authenticate with the server using the AuthUser and Password properties
- Make sure the FROM address you are sending from is a valid one, one which the server accepts.
External Exchange Failure
"I am using Exchange Server. Internal email sent from NetTalk works fine, but my external emails are never delivered."
Go to Internet mail service properties - routing tab - switch "reroute incoming smtp mail" to on.
EML file
"How do I create an EML file when sending emails"
The WholeMessage property contains the email in EML format. So you can just save this
property as a file. This is easy with StringTheory.
For example;
str StringTheory
str.SetValue(net.WholeMessage)
str.SaveFile('something.eml')
Class Reference
NetEmailSend
NetEmailReceive
NetIMAP
[End of this document]