Skip to content
Web

Users & Sessions

There are a number of settings in 3forge for fine-tuning the user experience on a session or user basis. This page contains information on how to set individual user and session preferences.

Users

Permissions

Permission control for different user groups can be done within 3forge such that only entitled users can see given windows in a dashboard.

For example, assuming admin and non-admin users, developers can use the Custom Callbacks feature to ensure appropriate user access:

For these two windows, only admins should be able to access the "Restricted" window. To set this up, see the instructions below.

  1. In developer mode, go to Dashboard -> Custom Callbacks.

  2. Navigate to the onStartup() tab and input the below AmiScript:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    string role = session.getProperty("ROLE");
    if (role != "Admin"){
        for (window w: session.getWindows()){
            if (w.getName()=="Restricted"){ 
                w.setType("HIDDEN");
                w.minimize();
            }
        }
    }
    

  3. Press "Submit." You should now find that non-admin/developer users cannot see the "Restricted" window:

Note

This example assumes the only user groups are admins and non-admins.

For more realistic user permissions, we recommend using the custom entitlements plugin to define the different user roles and then implement your custom callbacks accordingly.

Preferences

Dashboards can be shared among several users, however each individual user may have their own preferences they wish to implement on a shared file. This can apply to things like window scaling and position, divider settings, and the visual state of some table.

If user preferences are not enabled, when navigating to Accounts->My Developer Settings, you will see the following options grayed out.

To set up user preferences, a developer will need to assign a "namespace" to that given layout.

Setup

In developer mode (i.e, a user with developer permissions), navigate to Dashboard->Dashboard Settings with the layout that you want to have individual user preferences for.

Enter a namespace for the dashboard. This namespace will be used to save an individual user's preferences to the folder amione/data/users after they've logged in.

Where previously the preferences selections were grayed out, they should now be clickable. This is how a user can save their preferences.

Save Preferences

To save the dashboard state, navigate to Account->Save Preferences. When logging back into 3forge with that user, you will be prompted to load the dashboard according to the previous preferences.

Each user will have their own preferences on the state of a dashboard, but this will not impact other users' version of the same dashboard.

The saved preferences are stored in the users folder, by default located in amione/data/users with the format:

<username>.ami_prefs_<namespace>

These files can also be used to import/export different user preferences.

Note

Only users with dev permissions can set a namespace for a dashboard. Regular users will not be able to access or see this, but their preferences will be saved to file accordingly.

Settings

There a number of settings that are similar to preferences that can be used to set default behaviors in 3forge for different users.

These settings correspond to a number of things, like timezones, certain developer options, and other formatting options.

There are a few ways to set this:

  1. Programmatically:
    • Default settings for an 3forge instance which can be set in local.properties
    • For more information, see here
  2. Via access.txt:
    • Supply user settings as pipe-delimited variables
    • For example: timeZone=ACT
  3. Via the user ami_settings file:
    • Found under amione/data/users
    • These are JSON files with key-value pairs for specific settings
    • For example, "timeZone":"ACT"
  4. Within 3forge itself:
    • Under Account -> My Settings for user settings
    • Under Account -> Developer Settings for developer settings (dev users only)

Below is a table containing the current configurable user settings.

Setting Description Example (ami_settings File)
ami_layout_current
  • The current layout file that the user has open
  • When 3forge is reloaded for that user, this is the file that will launch
"ami_layout_current":"untitled.ami"
ami_layout_current_source
  • The source directory that the current layout is loaded from
  • None supplied by default, but valid options are ABSOLUTE,LOCAL,CLOUD, and SHARED
"ami_layout_current_source":"ABSOLUTE"
developer_ami_editor_keyboard
  • The editor type for AmiScript windows
  • Valid options are default and vi
"developer_ami_editor_keyboard":"vi"
developer_export_setting
  • The legibility of the exported JSON file for the developer settings
  • Valid options are compact, legible, and expanded
"developer_export_setting":"compact"
developer_logout
  • Behavior to exhibit on automated logout
  • Valid options are Debug, Logout, and Ignore
"developer_logout":"Debug"
debug_info_setting_key
  • How often to log information
  • Valid options are debug_only (when editor mode is on), always, and never
"debug_info_setting_key":"debug_only"
debug_warning_setting_key
  • How often to log warnings
  • Valid options are debug_only (when editor mode is on), always, and never
"debug_warning_setting_key":"always"
developer_headers
  • Whether the developer headers should be expanded or collapsed
  • Valid options are developer_headers_expand and developer_headers_collapse
"developer_headers":"developer_headers_expand"
show_setting_divider
  • Whether to show divider settings upon creation
  • Valid options are show_editor and hide_editor
"show_setting_divider":"show_editor"
show_style_editor_tabs
  • Whether to show tab settings upon creation
  • Valid options are show_editor and hide_editor
"show_style_editor_tabs":"hide_editor"
show_autosave_prompt
  • Whether the autosave prompt appears
  • Valid options are developer_autosave_show and developer_autosave_hide
"show_autosave_prompt":"developer_autosave_show"

These settings are primarily intended for developers and generally affect the developer experience in 3forge.

For more general user settings which determines things like number formats and other preferences, see the below table.

Note

The settings in this table are the same as the ones listed in the configuration guide and can be programmatically set to assign the default values for that 3forge session.

Setting Description Example (ami_settings File)
dateFormat
  • Format of date
  • Default is M/dd/yyyy
"dateFormat":"dd/MM/yyyy"
timeFormat
  • Format of time
  • Default is H:mm
"timeFormat":"hh:mm"
timeZone
  • Java-accepted timezone
  • Default is EST5EDT
"timeZone":"EST5EDT"
numberSeparator
  • Determines how a number is formatted
  • Default is 1,234,567,890.123
ami.default.user.numberSeparator=1,234,567,890
numberDecimalPrecision
  • The level of decimal precision
  • Valid options are between 0 and 10
"numberDecimalPrecision":"4"
sciNotDigitsLeft
  • For scientific notation, how many digits should be visible left of the decimal
  • Valid options range between 1-20
"sciNotDigitsLeft":"2"
sciNotDigitsRight
  • For scientific notation, how many digits should be visible right of the decimal
  • Valid options range between 1-20
"sciNotDigitsRight":"3"
numberNegativeFormat
  • Format of negative numbers
  • Valid options are sign or parentheses
"numberNegativeFormat":"sign"
spreadSheetFormatOption
  • Spread sheet formatting
  • Valid options are always or never
"spreadSheetFormatOption":"always"
autoApplyUserPrefs
  • Whether or not to automatically apply user preferences
  • Valid options are always, never or ask
"autoApplyUserPrefs":"ask"
defaultFileBrowserPath
  • Path to files that are loaded into 3forge
"defaultFileBrowserPath":"C:/mypc/ami/amione"

Web Resources

Users can upload files and datasources within the Web to a centralized resources hub. This is accessible to those with access to that Web instance and is not limited to the session.

In the Resource Manager window, you can view files available to the web instance as well as upload any of your own files.

These will then be stored in a web_resources directory of the Web instance's installation, typically under amione/web_resources.

To change this directory, you will need to change the following property to a directory of your choosing:

ami.web.resources.dir=web_resources

AMI Center Sessions

Note

Both the Center and Web have and manage sessions which are independent of each other. For Web sessions, see this section.

Sessions manage the various parts of the Center. To view Center session information, run the SHOW SESSIONS command in the AMIDB shell tool:

There are typically 4 different types of AMI Center session:

  1. __SYSTEM : effectively the parent session, sitting on top of the session hierarchy.

  2. __RTFEED : the session that manages all realtime feeds.

  3. __SCHEDULER : sessions that are associated to timers. Each timer has a unique __SCHEDULER session associated to it.

  4. The AMIDB shell tool and any console will also have a session associated to it.

AMI Web Sessions

A Web Session is created every time a user logs in to the frontend dashboard. The session is usually associated to a user login, however it is possible to have headless sessions that are not owned by any given user.

Each Web session has an associated unique __SESSIONID. You can view this within a session's layout via Dashboard -> Session Variables, or through the f1 console.

Note

For more information on retrieving web information via the f1 console, see the section below.

Multiple Sessions

A single AMI instance can have multiple Web sessions:

  1. When a user has multiple logins

    • A single user can log in and access the same dashboard from different browsers.
    • E.g, for a user logging into a session from two browsers:

      There are two login records (__LOGINID) for the same username in the f1 console.
  2. When a user opens or starts multiple sessions within an AMI instance

    • Multiple sessions per browser can be configured using the property ami.web.default.MAXSESSIONS.
    • If set to 2 or higher, a user can create a new session with the same login credentials. This can be done in two ways:
      1. Within AMI Web, click Account->Start New Session to start a new session in the same browser.
      2. In the Session Chooser page (after logging in, or accessing the main 3forge application page), click the "Start a new session" button.
    • E.g, for a user with two sessions in the same browser:
  3. When there are headless sessions associated to the Web instance

    • Headless sessions are not associated to a single user but to the Web instance itself.
    • Instructions for setting up headless sessions are listed directly in the section below

Headless Sessions

Setup

A headless session is a session that doesn't belong to any one user. Instead, it belongs to the 3forge instance itself. If a user logs out, the headless session will remain available for other users for as long as that instance is active.

To create a headless session, you will need to edit the headless.txt file in amione/data which is supplied by default with a 3forge installation.

The file contains the following text with instructions on using headless sessions:

1
2
3
#Each line represents a headless session. Syntax is: HEADLESSNAME|USERNAME|SCREEN_WIDTH x SCREENHEIGHT|Key1=Value1|Key2=Value2|....
#Start line with pound(#) for comment, start with bang(!) to not auto start session
#headless1|headlessdemo|2000x1000|ISDEV=true

Uncomment the final line (line 3) to create a headless session with the following properties:

  1. headless1

    • Name of the session
  2. headlessdemo

    • Username of the headless session
  3. 2000x1000

    • Screen resolution in width x height of the session
  4. ISDEV=true

    • Permissions of the session

When AMI is next launched, users will be able to access a headless session with these settings.

Note

Headless sessions will auto-start with AMI unless specified. To stop a headless session from automatically starting, prepend it with a ! in headless.txt:

!headless1|headlessdemo|2000x1000|ISDEV=true

Ownership

To work within a headless session, a user needs to "claim ownership" of that session temporarily. When finished, the session can then be released.

Before any user claims ownership of a headless session, the __LOGINID for a headless session will be null:

To claim temporary ownership of a session, you can do one of the following:
  1. Access a headless session via the Session Chooser (this will automatically assign the user ownership)

  2. Select the session from within Web via Account->Take ownership of headless session

    The headless session will now be tied to the current login:

To release ownership of a headless session, you can do one of the following:
  1. Log out (automatically releases the session)
  2. Remove the session in the Session Chooser (this will release it, not close it)

  3. Release ownership within the Web by clicking Account->Release ownership of headless session.

Managing Web Sessions (f1 Console)

Web sessions can be managed through the f1 console port.

Note

The default port for the f1 console is 3285. You can change this to a different unassigned port in local.properties with the following line:

f1.console.port=your_port_number

Listed below are the commands available that can be used in the f1 console

Commands

amiWebServer.showLogins()

Show all logins.

1
2
3
4
5
6
7
8
AmiOne>amiWebServer.showLogins()
 +----------+--------------------------+---------------------+--------+
 |__USERNAME|__LOGINID                 |__LOGINTIME(GMT)     |Sessions|
 +----------+--------------------------+---------------------+--------+
 |demo      |kn31R99Pz4QKayDlWhn8r1QfoJ|20251009 09:49:16.546|1       |
 +----------+--------------------------+---------------------+--------+

#EXECUTED: 0.01 second(s). 129.97 MB in use. Thu Oct 09 11:33:42 BST 2025
amiWebServer.showSessions()

Show all sessions.

AmiOne>amiWebServer.showSessions()
 +--------+------------+--------------------------+--------------------+---------+---------+--------------+-----+--------------------- +---------------------+-------+
 |Type    |__USERNAME  |__LOGINID                 |__SESSIONID         |__ADDRESS|__NAME   |Layout        |Label|__LOADTIME(GMT)      | LastAccessTime(GMT)  |Status |
 +--------+------------+--------------------------+--------------------+---------+---------+--------------+-----+--------------------- +---------------------+-------+
 |HEADLESS|headlessdemo!null                      |aNyZFu3CQmgKt0XjlmT5!null     |headless1!null          !null |20251008 12:47:06.879|20251009  10:34:13.942|ENABLED|
 |USER    |demo        |kn31o5eszTfeeYUf8CChzPrOlh|j1TFINBcZCYVowM5E3t9|127.0.0.1|Session 2|new_layout.ami!null |20251009 10:33:35.051|20251009  10:33:40.489|ENABLED|
 |USER    |demo        |kn31o5eszTfeeYUf8CChzPrOlh|0KDVdCJy9YqUx4VzZRPO|127.0.0.1|Session 1|new_layout.ami!null |20251009 10:27:15.403|20251009  10:33:38.393|ENABLED|
 +--------+------------+--------------------------+--------------------+---------+---------+--------------+-----+--------------------- +---------------------+-------+

#EXECUTED: 0.01 second(s). 127.18 MB in use. Thu Oct 09 11:34:14 BST 2025
amiWebServer.killSession(String sessionId)

Kill a user session.

1
2
3
AmiOne>amiWebServer.killSession("j1TFINBcZCYVowM5E3t9")
 killed
#EXECUTED: 0.00 second(s). 106.75 MB in use. Thu Oct 09 11:35:30 BST 2025
amiWebServer.createHeadlessSession(String sessionName, String username, String resolution, String attributes)

Creates a headless session with parameters matching the format shown for headless sessions above.

Any attributes should be supplied in a pipe-delimited list of key-value pairs.

1
2
3
AmiOne>amiWebServer.createHeadlessSession("headless2","headlessdemo", "2000x1000","ISDEV=true|ISADMIN=true")
 headless session created and enabled
#EXECUTED: 0.06 second(s). 148.25 MB in use. Thu Oct 09 11:36:26 BST 2025

Note

This will modify your headless.txt file.

amiWebServer.disableHeadlessSession(String name)

Disables a headless session.

1
2
3
AmiOne>amiWebServer.disableHeadlessSession("headless2")                         
 headless session disabled
#EXECUTED: 0.01 second(s). 95.06 MB in use. Thu Oct 09 11:38:38 BST 2025
amiWebServer.deleteHeadlessSession(String sessionName)

Delete a headless session. You will need to disable it first with amiWebServer.disableHeadlessSession(String name).

1
2
3
AmiOne>amiWebServer.deleteHeadlessSession("headless2")
 headless session deleted
#EXECUTED: 0.00 second(s). 127.09 MB in use. Thu Oct 09 11:39:34 BST 2025
amiWebServer.describeHeadlessSession(String sessionName)

Print the headless session details as it is saved in headless.txt.

1
2
3
AmiOne>amiWebServer.describeHeadlessSession("headless1")
 headless1|headlessdemo|2000x1000|ISDEV=true
#EXECUTED: 0.00 second(s). 153.53 MB in use. Thu Oct 09 11:40:20 BST 2025
amiWebServer.enableHeadlessSession(String sessionName)

Enable a headless session.

1
2
3
AmiOne>amiWebServer.enableHeadlessSession("headless2")
 headless session enabled
#EXECUTED: 0.04 second(s). 139.67 MB in use. Thu Oct 09 11:41:31 BST 2025
amiWebServer.killLogin(String uid)

Kill user login.

1
2
3
AmiOne>amiWebServer.killLogin("kn31o5eszTfeeYUf8CChzPrOlh")
 killed user login
#EXECUTED: 0.00 second(s). 140.97 MB in use. Thu Oct 09 11:43:25 BST 2025
amiWebServer.showPanels(String sessionId)

Show all panels.

AmiOne>amiWebServer.showPanels("0KDVdCJy9YqUx4VzZRPO")
 +------------------------+-------------+---------+-------+-----+------+---------+
 |Structure               |Type         |PanelId  |Visible|Width|Height|Transient|
 +------------------------+-------------+---------+-------+-----+------+---------+
 |Desktop - 3forge Website|Main Window  !null     |true   |1920 |852   !null     |
 | Inner Desktop          |Inner Desktop!null     |true   |1920 |824   !null     |
 |  Window - Window       |HTML         |Html1    |true   |960  |412   |false    |
 |  Window - Window - 2   |Table        |datamodel|true   |960  |412   |false    |
 +------------------------+-------------+---------+-------+-----+------+---------+

#EXECUTED: 0.01 second(s). 103.55 MB in use. Thu Oct 09 11:45:28 BST 2025
amiWebServer.exec(String sessionId, String script)

Execute AmiScript.

1
2
3
AmiOne>amiWebServer.exec("0KDVdCJy9YqUx4VzZRPO","round(2.3)")
 2
#EXECUTED: 0.00 second(s). 121.92 MB in use. Thu Oct 09 11:49:09 BST 2025

CPU Resource Management

To see if a particular user session is using excessive CPU resources, you can run the following commands:

  1. Run container_amiWeb.showPartitions() in the f1 console.
    This will return a table with the active partitions of the web container.
    AmiOne>container_amiWeb.showPartitions()
    +--------------------+-----------------+------------+-------+-------+------+-----------+----------+-----------+------------+
    |id                  |startTime        |threadpoolId|states |actions|queued|timeSpentMs|exceptions|writeLocked|inThreadPool|
    |String              |String           |String      |Integer|Integer|Long  |Long       |Integer   |Boolean    |Boolean     |
    +--------------------+-----------------+------------+-------+-------+------+-----------+----------+-----------+------------+
    |USERLOGIN           |20251008-12:47:32|F1POOL      |1      |6      |0     |49         |0         |false      |false       |
    |ivV6orz3608hnsyhDsXn|20251009-10:43:46|F1POOL      |1      |183    |0     |84         |0         |false      |false       |
    |PMYKfgbCQTUaROZD4Zdg|20251009-10:41:31|F1POOL      |1      |191    |0     |52         |0         |false      |false       |
    |SNAPSHOT_PARTITION  |20251008-12:47:08|F1POOL      |1      |756    |0     |123        |0         |false      |false       |
    |AMI_CENTER_CLIENT_1 |20251008-12:47:03|F1POOL      |1      |794    |0     |191        |0         |false      |false       |
    |PORTLET_BACKEND     |20251008-12:47:06|F1POOL      |1      |806    |0     |49         |0         |false      |false       |
    +--------------------+-----------------+------------+-------+-------+------+-----------+----------+-----------+------------+
    
    #EXECUTED: 0.03 second(s). 108.03 MB in use. Thu Oct 09 11:43:56 BST 2025
    
  2. To then determine which user corresponds to which ID, use the command: amiWebServer.showSessions():
    1
    2
    3
    4
    5
    6
    7
    8
    9
    AmiOne>amiWebServer.showSessions()
    +--------+------------+--------------------------+--------------------+---------+---------+--------------+-----+---------------------+---------------------+-------+
    |Type    |__USERNAME  |__LOGINID                 |__SESSIONID         |__ADDRESS|__NAME   |Layout        |Label|__LOADTIME(GMT)      |LastAccessTime(GMT)  |Status |
    +--------+------------+--------------------------+--------------------+---------+---------+--------------+-----+---------------------+---------------------+-------+
    |HEADLESS|headlessdemo!null                      |PMYKfgbCQTUaROZD4Zdg!null     |headless1!null          !null |20251008 12:47:06.879|20251009 11:44:52.231|ENABLED|
    |USER    |demo        |kn31RIkxxPedN2XwCRnq7EiJmc|ivV6orz3608hnsyhDsXn|127.0.0.1|Session 1|new_layout.ami!null |20251009 10:43:46.947|20251009 11:44:52.363|ENABLED|
    +--------+------------+--------------------------+--------------------+---------+---------+--------------+-----+---------------------+---------------------+-------+
    
    #EXECUTED: 0.02 second(s). 139.76 MB in use. Thu Oct 09 12:44:52 BST 2025
    

    The session ID will match to the ID of that user's partition in the web container.

  3. You can then kill any logins that are causing excessive overhead with amiWebServer.killLogin("<__LOGINID>").

Tip

To see a full list of the different methods that can be called in the console for each object, you can run the command show object <AMI_OBJECT>.

For example: show object amiWebServer will return a table of the methods associated with amiWebServer and their descriptions.

Generating Reports

3forge supports converting layout elements like charts, tables, and more into PDF reports. These can be distributed in a number of ways from within a dashboard:

  • Saved to a file system
  • Sent via email
  • Sent to an SFTP server

Create a PDF Report

The AmiScript class PdfBuilder is used to construct PDF documents from within the Web. It can be called from any Web element that takes AmiScript, e.g: a datamodel.

Example

Enter the following AmiScript into a datamodel to build a 2-page PDF:

{
    PdfBuilder pdb = new PdfBuilder(); 

    // Configuring the PDF's page settings
    pdb.setPageMargin(0.25,1,0.25,1,0,0);
    pdb.setFont(".14 normal #ffffff");
    pdb.setPageBackground("#073763");
    pdb.setHorizontalAlignment("LEFT");

    // Adding text and images 
    Binary img = mychart.toImagePng(1000,1000,true);
    pdb.appendText("Hello World");
    pdb.appendImage(img,null);
    pdb.appendPageBreak();
    pdb.appendText("Some text on the second page!");

    // Build the PDF
    Binary file = pdb.build();

    // Export the file
    FileSystem fs = session.getFileSystem();
    String dt = formatDate(timestamp(), "yyyy-MM-dd", "UTC");
    String saveFile = "reports/charts ${dt}.pdf";
    fs.writeBinaryFile(saveFile, file, false);  
}

Running the datamodel will do the following:

  1. Creates a new "reports" directory in amione as amione/reports
  2. Creates a file named charts yyyy-MM-dd.pdf (replacing the date format with the current date) containing the following:

    • The text "Hello World" followed by a chart from the layout
    • A second page with the text "Some text on the second page!"

Distributing PDF Reports

After building a PDF file in AMI, you can then choose how to distribute that file.

The PDF can be saved to a directory on the local file system. This is demonstrated in the example above.

To save the file locally, you will need a FileSystem object to write the data to disk:

1
2
3
4
5
6
7
// Naming convention for the PDF report 
String dt = formatDate(timestamp(), "yyyy-MM-dd", "UTC");
String saveFile = "reports/charts ${dt}.pdf";

// Save the PDF to disk
FileSystem fs = session.getFileSystem();
fs.writeBinaryFile(saveFile, pdf, false);

To send reports via email, you will need to configure your 3forge instance for email compatibility. Add the following properties to your local.properties file:

1
2
3
4
email.client.host=<smtp_mail_host>;
email.client.port=<mail_port>;
email.client.username=<sender_username_email>;
email.client.password=<sender_password_token>;

Note

Different email providers have different requirements. Ensure you have configured your email to use SMTP correctly before using it in 3forge.

To send the report via email, add the following AmiScript to your PDF builder, replacing the relevant fields:

session.sendEmailSync("test@gmail.com", new List("test@gmail.com"), "Report", false, "Body", new List("report.pdf"), new List(file), null, null);

The report can also be shared via a SFTP connection using the 3forge SFTP datasource adapter.

Add your SFTP server by navigating to Dashboard -> Data Modeler -> Attach Datasource and select SFTP from the datasource list. Input your server details, then add the following AmiScript to your PDF builder, replacing the datasource name with your details:

use ds=SFTPServer insert `reports/report.pdf` from select file as text;

This will upload the PDF to the SFTP datasource at the path reports/report.pdf.

Automated Reports with Headless Sessions

Reports can be automatically generated and sent out on schedule from an AMI Web server. This setup uses a datamodel on a timer to generate the reports in a headless session.

By using a headless session, the layout is associated to the Web instance rather than a specific user session. This ensures that even when a user logs out, the datamodel generating reports still continues to run.

Step-by-Step Guide

  1. Set up a headless session using the steps above with details like the following:

    reportgensession|reportgen|2000x1000|ISDEV=true
    
  2. Start 3forge and take ownership of the headless session.

  3. Create a datamodel for generating the report in Dashboard -> Data Modeler. See the example AmiScript above.
  4. Within the datamodel creation window, set the datamodel to run on a timer by clicking on the "Timers" button in the bottom right-hand side of the wizard:

    This will open the Timers interface which accepts times or crontab formatted entries. For example:

    • The input 14:30:00 or 14:30 will run the datamodel daily at 2:30 PM
    • The input crontab input 0 */2 * * * * will run every two minutes

    Click "Test (alt+enter)" to view upcoming runtimes:

  5. Once configured, submit the timer and finish the datamodel. Save the layout and release the session.

The report generator will now keep running in the headless session.

Embed Charts Directly in Email Body

Charts can also be embedded directly into the body of an email using HTML, rather than as a PDF attachment.

This works by using the AmiScript method sendEmail() and doing the following:

  1. Converting the chart into an image. The binary information will be passed as the attachmentDatas parameter.
  2. Embedding the information into HTML which is passed as the Body parameter.
  3. Ensuring that the isHtml parameter is set to true.

Example

1
2
3
4
ChartPanel vBar = layout.getPanel("vBar");
Binary vBarImg = vBar.toImagePng(1000,1000,true);
String htmlStr = "<img src=\"cid:vBarImg.png\" alt=\"Vertical Bar Graph\" width=\"450\" height=\"450\">";
session.sendEmail("test@gmail.com",new List("test@gmail.com"),"Report", true, "${htmlStr}",new List("vBarImg.png"), new List(vBarImg),null,null);

The body/content of the email corresponds to the HTML description of the embedded chart, contained in the variable htmlStr. The actual binary data of the chart, supplied as a .png image, is sent as the attachment.

The filename given to the chart on generation is used as the cid in the <img src> tag of the email body.

Embed Tables Directly in Email Body

Tables can also be directly embedded into the body of an email using HTML.

Create a custom method that converts the table into an HTML representation, which can then be used in the body of an email.

Example

String createTableElement(Table t) {
    String tableHtml = "<tr style=\"background-color: #3E4B4F;color:#FFFFFF\">";
    for (String colName: t.getColumnNames()) {
        tableHtml += "<th style=\"width:110px; height:20px; border: 1px solid;\"> ${colName} </th>";
    }
    tableHtml += "</tr>";

    for (Row r: t.getRows()){
        tableHtml += "<tr>";
        for (int i = 0; i < r.size(); i++) {
        String cell = r.getValueAt(i);
        tableHtml += "<td style=\" background-color: #3A3A3A;color:#FFFFFF;width:110px; height:20px; border: 1px solid;\"> ${cell} </td>";
        }
        tableHtml += "</tr>";
    }
    return tableHtml;
    };

Then call this method on the table you wish to embed:

1
2
3
4
5
TablePanel tab = layout.getPanel("Opp");
Table t = tab.asFormattedTable(true,true,true,true,false);
String table = createTableElement(t); //HTML conversion using our custom method
String htmlStr = "<table style=\"border: 1px solid;background-color: #D6EEEE;\"> ${table} </table> <img src=\"cid:vBarImg.png\" alt=\"Vertical Bar Graph\" width=\"450\" height=\"450\">";
session.sendEmail("test@gmail.com",new List("test@gmail.com"),"Report", true, "${htmlStr}",new List("vBarImg.png"), new List(vBarImg),null,null);

In this example, both a table and chart are being embedded in the email body, represented by the string variable htmlStr.