Every program attempts to expand until it can read mail. Those programs which cannot so expand are replaced by ones which can.The 360Works Email Plugin offers the following advantages over FileMaker's built-in mail functionality:
-Jamie Zawinski's Law of Software Envelopment
Set Variable [ $result = EmailRegister( "mylicensekey", "My Company" ) and EmailConnectSMTP( "mail.example.com" ) and EmailQuickSend( Email::from ; // required "from" address Email::to ; // comma-separated list of addresses Email::subject ; // subject of the message Email::body ; // message body Email::attach // path or URL or container to attach ) and EmailDisconnect ]Sending a plain-text email with one attachment:
Set Variable [ $result = EmailRegister("myLicenseKey"; "My Company") and EmailConnectSMTP( "mail.example.com" ) and EmailCreate( Email::from ; Email::to ; Email::subject ) and EmailSetBody( Email::body ; "plain" ) and EmailAttachFile( $attachment ) and EmailSend and EmailDisconnect ]Sending an HTML-formatted email (converts formatted FileMaker text to HTML using the
GetAsCSS
function):
Set Variable [ $result = EmailRegister("myLicenseKey"; "My Company") and EmailConnectSMTP( "mail.example.com" ) and EmailCreate( Email::from ; Email::to ; Email::subject ) and EmailSetBody( GetAsCSS( Email::body ); "html" ) and EmailSend and EmailDisconnect ]Sending a single message multiple times to different recipients can be done by creating a message using EmailCreate, then calling EmailRecipients and EmailSend multiple times. If you are sending large messages with attachments, this avoids the overhead of creating a separate message for each recipient. You can also send a single message to multiple TO, CC, or BCC recipients by passing a comma-separated list of addresses. Note: Email is sent from whichever machine the plugin is being used on, be sure to open up port 25 for outgoing SMTP access on those machines.
file:///path/to/attachment.jpg
).
set variable $registerResult = EmailRegister ( license ; company ) // check for registration success here set variable $connectResult = EmailConnectIMAP( server ; username ; password ) // check for connection success here set variable $$importUrl = EmailReadMessages ( "mailbox=INBOX" ; "viewed=false" ; "max=25" ; "attachments=true" ) // check for import success here If [$$importUrl = "ERROR"] Show Custom Dialog [EmailLastError] Exit Script End If // Import the email messages from the local XML file // which was created by the EmailReadMessages function Import records [$$importUrl ; Update Matching] // disconnect from the IMAP server set variable $disconnect = EmailDisconnect If [$disconnect = "ERROR"] Show Custom Dialog [EmailLastError] Exit Script End If
If you're running on FileMaker server or via IWP/CWP, you'll need to iterate over the messages, since [Import XML] is not a web-safe script step. The general pattern looks like this:
set variable $$importUrl = EmailReadMessages ( "mailbox=INBOX" ; "viewed=false" ; "max=25" ; "attachments=true" // check for import success here Loop Exit Loop If [not EmailGetNextMessage] New Record/Request Set Field[ImportedMessage::date ; EmailReadMessageValue( "dateSent" )] Set Field[ImportedMessage::from ; EmailReadMessageValue( "from" )] Set Field[ImportedMessage::to ; EmailReadMessageValue( "to" )] Set Field[ImportedMessage::subject ; EmailReadMessageValue( "subject" )] Set Field[ImportedMessage::body ; EmailReadMessageValue( "body" )] Set Field[ImportedMessage::messageId ; EmailReadMessageValue( "messageId" )] End Loop
readonly=false
.
Note: setting readonly=false
will cause any fetched messages to be marked as "viewed"! Then iterate to a message using the EmailGetNextMessage function.
Finally, use the EmailMessageSetFlag function to apply flags to a message (such as deleted, flagged, viewed, etc).
viewed
(by setting readonly=false
).
Additionally, any messages from a certain address are marked as deleted
:
Set Variable [ $result = EmailReadMessages( "viewed=false" ; "readonly=false" ) ] If [$result = "ERROR"] # Handle Error Here... End If Loop Exit Loop If [not EmailGetNextMessage] Set Variable[$result ; EmailMessageSetFlag("viewed") If [EmailReadMessageValue("from") = "deleteme@example.com"] Set Variable[$result ; EmailMessageSetFlag("deleted") End If End Loop
When something unexpected happens, a plugin function returns a result of "ERROR"
. This makes it easy to check for errors.
If a plugin function returns "ERROR", call the EmailLastError
function to get a detailed description of what went wrong.
Here is an example of basic error reporting:
Set Variable [ $result = MyPluginFunction("x" ; "y" ; "z") ] If [ $result = "ERROR" ] Show Custom Dialog [ "An error occurred: " & EmailLastError ] End If
Since the string "ERROR"
evaluates to false when evaluated by FileMaker, and most plugin functions return a 1
when successful, you can chain multiple dependent plugin operations together using the "and"
operator.
However, in this case the result will be a 1
or a 0
, not "ERROR"
. For example:
// chain multiple calls together
// if any of the functions fail, the calculation will
// short-circuit with a result of false
,
// and none of the subsequent function calls will be evaluated.
Set Variable [ $success =
FirstPluginFunction("x") and
SecondPluginFunction("y") and
ThirdPluginFunction("z")
]
If [not $success]
Show Custom Dialog [ "An error occurred: " & EmailLastError ]
End If
Note: the above only works for plugin functions which return 1
on success! Check the documentation for each function used in this manner.
If a plugin is not installed correctly, calls to a plugin function will return "?". As part of your startup script, you should check for this occurrence and display a warning accordingly that the plugin needs to be installed. Note: when treated as a boolean true/false value, FileMaker will treat ?
as true
.
FileMaker version 7 or higher.
Java Virtual Machine (JVM) version 1.5 or later. If you are running a JVM earlier than 1.5, you should upgrade.
Download a JVM from http://www.java.com/en/download/. If you are not sure what
version of Java you have installed, you can do java -version
on the command line in Windows or OS X.
Windows, or Mac OS X version 10.4 or higher.
Note to intel Mac users: running this plugin under Rosetta is not supported. Upgrade to FileMaker 8.5 to run our plugin in native Intel mode.
Drag the plugin from the MAC or WIN folder into your FileMaker extensions, and restart FileMaker.
This will also enable the plugin for use with Instant Web Publishing from the FileMaker Pro client software.
If the plugin does not load correctly, double-check that you meet the system requirements.
You do not need to do this step unless you plan on using the plugin with Instant Web Publishing or Custom Web Publishing with FileMaker Server Advanced. You will need an Enterprise License to use this feature.
For installing into the Web Publishing Engine with FileMaker Server or FileMaker Server Advanced, drag the plugin from the MAC or WIN folder
into the FileMaker Server/Web Publishing/publishing-engine/wpc/Plugins
folder. If there is no Plugins
folder inside the wpc
folder, then create it manually.
Restart FileMaker Web Publishing, and now the plugins should be ready to go.
Note that due to a bug which we and other plugin vendors have reported to FileMaker, web plugins do not work in FileMaker Web Publishing Engine 8.0v4 on Mac OS X. You will need to use a later version, like 9, or an earlier version, like 8.0v3. The Windows FileMaker Server 8.0v4 does not have this bug, and will work correctly.
The easiest way to test whether the plugin is working is to have a calculation which calls the version function of the plugin, and display that on an IWP layout. If it shows "?", then the plugin is not working. If it shows a number, then the plugin has been installed successfully.
You do not need to do this step unless you plan on using the plugin with scheduled script triggering, a new feature in FileMaker Server 9. You will need an Enterprise License to use this feature.
/Library/FileMaker Server/Database Server/Extensions
folder.
On Windows, this is at C:\Program Files\FileMaker\FileMaker Server\Database Server\Extensions
.Configuration -> Database Server->Server Plug-ins
and check the box that says 'Enable FileMaker Server to use plug-ins', and then check the 'enabled' box for this plugin.
Click the 'save' button and wait a few seconds to make sure that the 'enabled' check box stays checked. If it does not, then there was an error loading the plugin and you should contact us for help troubleshooting.
You should now be able to write schedules that trigger scripts which use the plugin.360Works has created an AutoUpdate helper database which makes setting up Auto Update much easier. This file includes pre-configured plugin files which you can place on your server, and an auto-update script for each of our plugins which you can paste into your own solution.
You can get the AutoUpdate360Works file at fmp7://autoupdate.360works.com/AutoUpdate360Works. Follow the instructions included in the file to either host your own Auto Update server or pull the files from ours.
Plugins will run in demo mode until they are registered. While running in Demo mode, the product will run for 2 hours every time you launch FileMaker / FileMaker Server / FileMaker Web Publishing Engine. The 2 hour time limit will reset every time you relaunch FileMaker. There is no expiration date when Demo mode stops working. There are no feature differences between the Demo version and the licensed version.
Once you have purchased the plugin, you can register it with the license key. Once a valid license key is entered, the product will run for as long as FileMaker is running. After FileMaker starts up with the plugin installed, open FileMaker preferences, click on the Plug-ins tab, select the plugin from the list, and click the Configure button. Enter your license key and company name in this dialog. You will only need to do this once on a given machine. Alternately, you can use the registration function to register the plugin during a startup script.
Note that if you are running the plugin with FileMaker Server / FileMaker Web Publishing Engine, you must use the registration function to register the plugin, since there is no preferences dialog on FileMaker Server to enter the license key and company name.
We love to hear your suggestions for improving our products! If you are experiencing problems with this plugin, or have a feature request, or are happy with it, we'd appreciate hearing about it. Send us a message on our website, or email us!
EmailReadMessages
function.EmailGetNextMessage
function.EmailAttachFile("http://localhost:8080/SuperContainer/123/RawData");-or-
EmailAttachFile("file:///path/to/invoice.pdf");-or-
EmailAttachFile("/Macintosh HD/path/to/invoice.pdf");-or-
EmailAttachFile(myTable::myContainerField);You can call this multiple times to attach multiple files to a message. Note on paths vs urls: This function can also accept a path (/path/to/file) instead of a file URL (file://path/to/file). This is handy for attaching PDFs generated by FileMaker. If called on a machine running Mac OS X, a file URL is created from a path by prepending the directory
/Volumes
to the supplied path, since FileMaker includes the hard drive name in paths.
For example, /MacintoshHD/Users/John Smith/Documents/
is converted to the file URL file:///Volumes/MacintoshHD/Users/John Smith/Documents/
.
data
- a path to a file, or a URL pointing to a file to attach to the message.EmailCreate("to@example.com"; "from@example.com"; "My Newsletter") and EmailSetBody( "<html><body><img src=\"cid:headergif123\">" & "This is an HTML message with embedded images
" & "<img src=\"cid:footergif456\">" & "</body></html>"; "html" ) and EmailAttachFileInline( Globals::headerContainer ; "headergif123" ) and EmailAttachFileInline( Globals::footerContainer ; "footergif456" ) and EmailSend
cid:contentid
, where contentid
is an arbitrary unique string you create for each inline attachment.
Your contentIds should be globally unique for a given image/file resource, as mail clients will use this to cache the contents of the message.
You should only use letters and numbers for your content ids, some mail clients have trouble with other characters.
data
- a path to a file, or a URL pointing to a file to attach to the message (see EmailAttachFile for valid arguments).contentId
- contentId of the attachment.append
to true if doing this).
bcc_addresses
- comma-separated list of addressesappend
- whether to append the new addresses to existing ones, or overwrite them.searchString
each time.
Once a message is sent, the replaced values are reset to their original values.
This is useful if you are using EmailSetBodyFile to load static HTML content as the body part, but want to insert dynamic content in the body. Or, if you are sending many emails and want to merge data into a static body text field.
searchString
- the text to replacereplaceString
- the replacement textappend
to true if doing this).
cc_addresses
- comma-separated list of addressesappend
- whether to append the new addresses to existing ones, or overwrite them.host_address
- the SMTP host address. This parameter may contain a port number using a colon syntax, e.g. smtp.example.com:2525
user
- The optional SMTP authentication usernamepassword
- The optional SMTP authentication passwordEmailConnectPOP
) must be called before reading email messages from the server.
This establishes a connection to the email server. When you are finished getting/sending email, it is a good idea to call EmailDisconnect to close the connection.
Here is an example of connecting to a regular mail server:
Set Variable[$result = EmailConnectIMAP( "my_email_host" ; "username" ; "password" ) ]
"ssl=1"
. If you are connecting to GMail, SSL encryption is required.
Here is an example of connecting to google mail (gmail) with SSL encryption:
Set Variable[$result = EmailConnectIMAP( "imap.gmail.com" ; "username" ; "password" ; "ssl=1" ) ]
host
- the IMAP host address. This parameter may contain a port number using a colon syntax, e.g. imap.example.com:2525
username
- The authentication usernamepassword
- The authentication passwordargs
- Additional optional arguments (ssl).EmailConnectIMAP
) must be called before reading email messages from the server.
This establishes a connection to the email server. When you are finished getting/sending email, it is a good idea to call EmailDisconnect to close the connection.
Here is an example of connecting to a regular mail server:
Set Variable[$result = EmailConnectPOP( "my_email_host" ; "username" ; "password" ) ]
"ssl=1"
. If you are connecting to GMail, SSL encryption is required.
Here is an example of connecting to google mail (gmail) with SSL encryption:
Set Variable[$result = EmailConnectPOP( "pop.gmail.com" ; "username" ; "password" ; "ssl=1" ) ]
host
- the POP host address. This parameter may contain a port number using a colon syntax, e.g. pop.example.com:2525
username
- The authentication usernamepassword
- The authentication passwordargs
- Additional optional arguments (ssl).Set Variable[$result = EmailConnectSMTP( "my_email_host" ; "username" ; "password" ) ]
"ssl=1"
. If you are connecting to GMail, SSL encryption is required.
Here is an example of connecting to google mail (gmail) with SSL encryption:
Set Variable[$result = EmailConnectSMTP( "smtp.gmail.com:465" ; "username" ; "password" ; "ssl=1" ) ]
host
- the SMTP host address. This parameter may contain a port number using a colon syntax, e.g. smtp.example.com:2525
username
- The optional SMTP authentication usernamepassword
- The optional SMTP authentication passwordargs
- Additional optional arguments (ssl).from
- the FROM address for the new message. Use "Name <you@domain.com>" for displaying the name instead.to
- the TO address for the new messagesubject
- the SUBJECT of the new messageEmailReadMessages
function.
To use this function, first call EmailReadMessages
with the appropriate parameters.
Next, call EmailGetNextMessage
, which returns 1 or 0 depending on whether a message was loaded.
Finally, call EmailReadMessageValue
to get individual properties of the currently loaded message.
""
if there was no error.
parent
- optional mailbox to traverse. If not specified/empty, the root mailbox is used.recursive
- optional parameter for whether to traverse sub-folders recursively. Default is false./
) character.
readonly=false
to use this function.
The allowed flags are:
POP vs IMAP. POP accounts typically do not support persistent flags, so if you flag a message as deleted
in a POP account,
it will be permanently deleted
when you disconnect from the server.
flag
- one of the named flags to setvalue
- the optional value to set the flag to. Default is 1
(or true
).from
- The "from" email address. Use "Name <you@domain.com>" for displaying the name instead.to
- A comma-separated list of "to" email addressessubject
- The subject of the messagebody
- The message body. If the body starts with <html
it is assumed to be an HTML-formatted message.attachment
- A container holding an attachment to include with the email, or a URL or path to a file to attach.attachments=true
as a parameter to the EmailReadMessages function.
After importing an email message into FileMaker, pass any attachment paths to this function to get container data for the attachment path.
For example, you might pass the following argument:
EmailReadAttachment( "/Macintosh HD/private/tmp/4545776.01203682301836.JavaMail.root@pluto.local/text.html" )The supplied path should not begin with
file:
, image:
, or any other prefix - just the path.
Note that this will actually work for any file, it doesn't need to be an email attachment.
path
- The path as returned in the email importpath
, or "ERROR" if an error occurred (use EmailLastError in this case)
If an error occurs, this function will return "ERROR". Use the EmailLastError function to get more information about the error.
The Email plugin supports reading messages from POP and IMAP mailboxes. Typically, you're interested in only fetching new messages from your mailbox. There are several approaches to doing this.
IMAP mailboxes assign each message a unique UID. When reading messages from an IMAP mailbox, you can get the value for this UID with the following function:
Set Field[ImportedMessage::uid ; EmailReadMessageValue( "uid" ) ]Once you have the UID of the most recently fetched message, you can pass that in as an argument to subsequent calls to EmailReadMessages, for example:
Go To Record/Request/Page [Last] Set Variable [ $result = EmailReadMessages ( "uid=" & ImportedMessage::uid ) ]This fetches only the messages whose UID is greater than the most recently fetched message. This is the preferred way to fetch new messages from an IMAP mailbox, as it is very efficient, doesn't modify any messages, and will work even if another email client accesses the mailbox.
You can specify a filter option to only search for unread messages:
Set Variable [ $result = EmailReadMessages ( "viewed=false" ; "readonly=false" ) ]
After fetching unread messages, you should then set the "viewed" flag to true
for each message, so subsequent reads will skip these messages. This is outlined in the following section "Reading Individual Messages"
Note: searching for unread messages will not work correctly if other email clients are accessing the same mailbox and marking messages as viewed.
This is similar to option 2, except you don't need to modify the messages on the server. Simple count how many messages have been fetched from the mailbox, and pass a skip
parameter to the EmailReadMessages
function whose value is this number.
Note: If messages are deleted from the mailbox, local messages should be deleted as well, so the local count
matches the number of fetched messages on the server.
After successfully calling EmailReadMessages, you can iterate over the fetched messages using the EmailGetNextMessage function. This pattern typically looks like this:
Loop Exit Loop If [not EmailGetNextMessage] New Record/Request Set Field[ImportedMessage::from ; EmailReadMessageValue( "from" )] Set Field[ImportedMessage::to ; EmailReadMessageValue( "to" )] Set Field[ImportedMessage::subject ; EmailReadMessageValue( "subject" )] Set Field[ImportedMessage::body ; EmailReadMessageValue( "body" )] Set Field[ImportedMessage::messageId ; EmailReadMessageValue( "messageId" )] // OPTIONAL: mark this messages as "viewed" // (You must pass readonly=false during EmailReadMessages to do this) Set Variable[$result ; EmailMessageSetFlag("viewed")] End Loop
To import email data into FileMaker via XML, use the "Import Records" script step, and specify an XML data source, passing the file URL returned from this function.
Use the "messageId" field in the resulting XML as a match field when defining import options.
Note: XML import is not a web-safe script. Use the method described in "Reading Individual Messages" if your script is running in IWP or on the server, or if you need to modify individual messages on the server.
key=value
arguments. You can specify any number of flags you wish.
The following is a description of the available flags:
INBOX
.false
, which disables attachment downloading. This is significantly faster.
If attachment downloading is disabled, you can still retrieve a list of the attachments in a message using the EmailReadMessageValue ( "attachments" )
function. You can the re-read the message at a later time to download the attachments (see the EmailClient.fp7 example file).
uid
is newer than the one passed in. This is very useful for only fetching new messages from IMAP mailboxes. When looping through new messages, call EmailReadMessageValue("uid")
on the last message and save this to a field in your database. Then when fetching new messages, pass this uid
in as a filter argument. Only newer messages will be returned. Note: if you specify this option and the mailbox is an IMAP mailbox, all other search filters (skip, max, to, from, date, etc) will be ignored.from
addressto
addresssubject
messageId
body
true
to return only previously viewed messages, false
to return only unread messages.true
to return only flagged messages, false
to return only non-flagged messages.true
to return only deleted messages, false
to return only non-deleted messages.true
(read-only).
If you plan on deleting, moving, or flagging any messages, use false
in this parameter.
Note: setting readonly=false
will cause any fetched messages to be marked as "viewed"!
For example, you might use the following to fetch the first 25 unread messages from your inbox:
EmailReadMessages( "mailbox=INBOX" ; "attachments=false" ; "max=25" ; "attachments=false" ; "viewed=false" )
flags
- optional flags which control how messages are read.EmailGetNextMessage
function.
If there are multiple values for a key, each value will be on a separate line.
The parameter must be one of the following values (case-insensitive):
attachments
parameter in EmailReadMessages
)You can retrieve any message header by using this function. For example, to get information about the mail application which sent the message, you can use EmailReadMessageValue("header:X-Mailer")
.
If a header has multiple values, they will be returned as a return-separated list.
key
- The key to retrieve, must be one of the above listed keys.append
to true if doing this).
to_addresses
- comma-separated list of addressesappend
- whether to append the new addresses to existing ones, or overwrite them.licenseKey
- a valid license key string.registeredTo
- the company name for the license key used.GetAsCSS
function to generate the HTML, e.g.
EmailCreate( "from@example.com", "to@example.com", "A multipart message" ) and EmailSetBody( Email::body ; "plain" ) // this is used for mail clients which don't display HTML and EmailSetBody( GetAsCSS( Email::body ); "html" ) // HTML version with formatting and EmailSend
body
- text to be displayed in the messagecontentType
- type of formatting used in the body, e.g. "plain", "html", "rtf".characterSet
- optional character settrue
as the embedResources
parameter, any images or stylesheets referenced in the email message will be included as inline attachments in the email message.
This means that users will not need to load the resources from the central server, but it can increase the email message size considerably.
If you pass false
as the embedResources
parameter, any referenced image URLs will be rewritten as absolute URLs.
This function also accepts .mhtml html archive files, which have the advantage of already having all images embedded in the file. The embedResources
parameter is always effectively true
for .mhtml files.
url
- URL to the HTML document.embedResources
- whether resources should be embedded in the HTML email or rewritten as absolute URLs.header
- the header namevalue
- the header valuesubject
- the email message subjectemail
- one or more email addresses to validate (comma-separated).email
is empty.