ROUNDCUBE PLUS EMAIL SCHEDULE PLUGIN
====================================

This plugin allows users to schedule the delivery of their email messages. Scheduled messages can be sent with a delay
or at a specified date and time.

REQUIREMENTS
------------

- PHP: 7.4 or higher
- Roundcube: 1.5, 1.6
- Database: MySQL / Postgres
- System: Cron job
- Config: Drafts enabled

DISCLAIMER
----------

This plugin initiates email delivery when triggered by a cron job. If the cron job or the plugin is not properly set up,
the scheduled emails will not be sent.

Please make sure that the plugin works properly before making it available to your users. If you choose to use it in a
production environment, we cannot be held liable for any damages caused by delayed, unsent, or lost email messages.

INSTALLATION
------------

1. Copy the directories xemail_schedule and xframework included in this package to the 'plugins' directory of your
   Roundcube installation.

2. Rename the file <roundcube>/plugins/xemail_schedule/config.inc.php.dist to config.inc.php.

3. Edit the file <roundcube>/plugins/xemail_schedule/config.inc.php and configure the plugin according to your needs.

4. Create a cron job that will trigger the scheduled email delivery (see the section below).

5. Edit the file <roundcube>/config/config.inc.php, add xemail_schedule to the plugins array, and specify your license
   key.

6. Make sure drafts_mbox_mbox is not unset in <roundcube>/config/config.inc.php. The plugin needs the draft folder
   enabled in order to edit scheduled messages. (Drafts_mbox is enabled by default.)

For more information on installing Roundcube Plus plugins, see:
https://roundcubeplus.com/helpdesk/knowledgebase.php?article=29

COMPATIBILITY / LIMITATIONS
---------------------------

1. This plugin has been created for the standard version of Roundcube as provided on the Roundcube website:
   https://roundcube.net It might not work properly with customized versions of Roundcube, including the version
   provided as part of the Kolab system. Please note that we cannot provide any technical support for the plugin
   deployed on a non-standard version of Roundcube.

2. This plugin will not work with SQLite because SQLite uses a separate database for each user. For the cron script to
   send scheduled messages, they need to exist in a common database table.

3. Scheduled emails will only be accessible from within Roundcube; they will not be accessible from any third-party
   programs that access the IMAP server directly (for example, Outlook, Thunderbird, etc.).

4. The plugin might not work properly with the Enigma plugin.

5. The plugin might not schedule email messages that contain very large media or attachment files.

CRON SETUP
----------

In order for the plugin to send scheduled messages, a cron job must be set up on the server. The cron job must run every
minute.

Please note that the plugin checks for the existence of a functional cron job and will disable email scheduling if it
does not detect one.

There are two ways to set up the cron job: execute a PHP CLI script or access a URL.

(The examples below assume you are using a Linux server.)

OPTION 1: Access a URL

Add the following to your crontab:

* * * * * wget -O - <roundcube_url>/?xemail-schedule-cron=1 >/dev/null 2>&1

Replace <roundcube_url> with the full URL path of your Roundcube installation.

This method is easier to set up, but it cannot be used under cPanel because cPanel requires a user to be logged in to
access Roundcube. If you are running Roundcube under cPanel, use OPTION 2 below. (Note that in order to use the Email
Scheduler, cPanel Roundcube must use MySQL or Postgres, it won't work with SQLite.)

OPTION 2: Execute a PHP script

A) Add the following to your crontab:

* * * * * php <roundcube_file_path>/plugins/xemail_schedule/cron.php

Replace <roundcube_file_path> with the absolute directory path of your Roundcube installation. (Under cPanel, Roundcube
is usually installed in /usr/local/cpanel/base/3rdparty/roundcube.)

Note that the version of PHP running on the command line has a separate configuration from the version running through
the web server. You must make sure that both versions are set to the same timezone, or the messages will be sent at the
wrong time.

B) Change the permissions of the file <roundcube_file_path>/logs/sendmail to 0666 to allow the PHP CLI access to the
sendmail log.

SMTP AUTHENTICATION
-------------------

When a user sends a message while logged in to Roundcube, the user's username and password are used to authenticate with
the SMTP server. But when cron is executed, there is no logged-in user, so no username and password are available. If
the SMTP server requires authentication, it will refuse to send the scheduled messages.

The plugin offers two solutions to this problem.

OPTION 1: Store credentials with scheduled messages

If you set this config option to true: xemail_schedule_store_credentials_with_messages, the plugin will store all of the
user's SMTP settings (server, port, SSL mode, HELO host, username, password) with the scheduled message in the database.
The settings will be stored encrypted and deleted when the message is sent.

This is the simplest solution and does not require any additional server configuration. The two downsides are:

a) The user's SMTP password is stored in the database (encrypted).
b) If the user changes their account password, the scheduled messages will fail to send, as the old password will be
   sent to the SMTP server.

OPTION 2: Use a common account for SMTP authentication

If you don't want to store user credentials in the database, you can set
xemail_schedule_store_credentials_with_messages to false, create a dummy email account, and set its credentials in the
config settings: xemail_schedule_smtp_user and xemail_schedule_smtp_pass.

In this case, the plugin will use the dummy account to authenticate with the SMTP server when sending messages for all
users.

The downside is that some servers require the authentication username to match the username in the "from" field of the
message being sent. If that is the case, you will see an error in your logs similar to: "Sender is not same as SMTP
authenticate username."

You may be able to fix this problem in your server's configuration. For example, here is the setting you can use to fix
this problem in iRedMail:

ALLOWED_LOGIN_MISMATCH_SENDERS = ['user@mydomain.com']

ATTACHMENT SIZE LIMITATIONS
---------------------------

To properly schedule messages, the Email Scheduler relies on Roundcube’s native mechanism that encodes and embeds
attachments in the email body. The maximum size of attachments that can be included depends on the PHP memory_limit
configuration. Roundcube uses the following formula to check if enough memory will be available for the process:

required_memory = total_attachment_size * 1.33 * 12

For example, the memory required to schedule a message with a 20 MB attachment is:

20 MB * 1.33 * 12 ≈ 320 MB

This means PHP must have at least 320 MB of memory available for Roundcube to properly encode the attachment. If your
server’s memory_limit is set lower than this value, the plugin will refuse to schedule the message and display an error,
preventing Roundcube from sending the message without the attachment.

To ensure attachments can be scheduled correctly, follow these steps:

1. On Roundcube’s compose page, check the “Maximum allowed file size” displayed.
2. Multiply that number by 1.33, then by 12.
3. Set the PHP memory_limit to a value larger than the result.

For example, if the maximum total file size allowed by Roundcube is 75 MB, the memory_limit value must be set to at
least:

75 MB * 1.33 * 12 ≈ 1,200 MB

If you cannot increase the memory_limit, lower the Roundcube max_message_size setting so that the maximum allowed file
size displayed on the compose page, when multiplied by 1.33 * 12, is smaller than your available memory_limit.

TECHNICAL EXPLANATION
---------------------

This section describes the technical details of the Email Scheduler operation.

When a user schedules a message, the plugin intercepts the email sending process and stores the message (along with
encoded attachments) in the table xemail_schedule_queue of the Roundcube database. A cron job running every minute
triggers the plugin's delivery system, which looks up the messages stored in the database and sends them at the correct
time.

Since the plugin might not have access to the individual IMAP accounts when sending messages, the copying of the
messages to the "sent" folder on the IMAP server is done the next time the user logs in to their Roundcube account.

The plugin keeps track of the cron execution time, and if it finds that the cron job has not executed within the last
120 seconds, it disables message scheduling and displays this note on the compose page: "Message scheduling is disabled.
Contact the administrator." This prevents users from scheduling messages that will never be sent.

This message is a clue for admins that the cron job is not functioning properly or it's not triggering the plugin's
delivery system. If you want to ensure that the delivery system itself works properly, you can manually navigate to this
URL in the browser:

<roundcube_url>/?xemail-schedule-cron=1

You should see stats showing how many messages have been sent as a result of this call.

The plugin will send all delayed messages when the delivery system is first triggered. In other words, if the cron job
has not been functioning properly and some scheduled messages were not sent, they will all be sent once the cron job is
fixed.

The cron job MUST run every minute. It's not possible to properly configure the plugin with cron jobs running every 5
or 10 minutes.

When the user edits a scheduled email, the email is saved as a draft on the IMAP server, removed from the database, and
edited using the compose page.

When the user deletes a scheduled email, the email is saved in the trash folder on the IMAP server (if enabled) and
removed from the database.

Since the scheduled messages are stored in the Roundcube database, this introduces two restrictions:

A) For the email scheduler to work properly, it must be running on a Roundcube installation that uses a single database,
   for example, MySQL or PostgreSQL. It won't work with SQLite, because Roundcube using SQLite (as in newer cPanel
   setups) might use multiple databases that the plugin's delivery system triggered by cron doesn't have access to.

B) The scheduled messages can't be accessed from third-party programs that connect to the IMAP server directly (Outlook,
   Thunderbird, etc.).

Technically, it would be possible to store scheduled messages directly on the IMAP server, but the complexity of the
setup, server constraints, and security risks associated with that approach would make the Email Scheduler plugin
practically unusable for the majority of setups. Storing the scheduled messages in the database makes the plugin
accessible and requires minimal setup, even if this approach introduces some minor limitations.

LICENSE
-------

This plugin is distributed under a commercial license. In order to use the plugin, you must purchase the license
from Tecorama LLC. See the LICENSE file for details.

COPYRIGHT
---------

Copyright (c) 2025, Tecorama LLC
