snappymail/plugins
2025-06-07 13:06:23 +02:00
..
add-x-originating-ip-header Improve plugin Description/README functionality 2021-03-04 12:15:11 +01:00
attachments-force-open Cleanup for #1489 2024-03-15 23:41:34 +01:00
auto-domain-grab Update plugins to use new Net/Imap/Smtp/Sieve Settings object 2022-11-11 14:32:24 +01:00
avatars Bump version for #1918 2025-03-10 16:35:27 +01:00
backup Some minor backup example extension changes for #1042 2024-03-18 16:28:54 +01:00
black-list By default throw AccountNotAllowed as confused in #1478 2024-03-04 10:12:59 +01:00
cache-apcu Resolve #1533 2024-03-31 21:06:39 +02:00
cache-memcache Resolve #1715 2024-09-15 17:42:17 +02:00
cache-redis PHP 8.4: Implicitly nullable parameter declarations deprecated 2024-09-17 15:58:37 +02:00
change-password Create uk.ini 2024-10-14 17:32:59 +03:00
change-password-cpanel Resolve #485 2024-03-19 17:31:32 +01:00
change-password-froxlor Removed unused ClientException 2024-03-19 17:30:20 +01:00
change-password-hestia Removed unused ClientException 2024-03-19 17:30:20 +01:00
change-password-hmailserver Removed unused ClientException 2024-03-19 17:30:20 +01:00
change-password-ispconfig Removed unused ClientException 2024-03-19 17:30:20 +01:00
change-password-mailcow Add change-password-mailcow driver 2024-07-25 10:37:09 +01:00
change-password-poppassd Removed unused ClientException 2024-03-19 17:30:20 +01:00
change-smtp-ehlo-message Merge all example plugins 2022-05-31 10:47:14 +02:00
compact-composer update squire to v2.3.2 and fix willPaste listener/sanitizer 2024-11-16 18:16:32 -05:00
contact-group-excel-paste Release plugins as tar.gz because PharData is more common then ZipArchive 2021-02-10 09:50:20 +01:00
custom-login-mapping Added the proper logging for #1706 2024-10-08 13:06:43 +02:00
custom-system-folders [snappymail] More changes to use the word "extensions" rather than plugins/packages 2021-08-27 23:49:03 +02:00
demo-account transitionend listen to opacity as top changed on resize of view 2024-07-07 23:33:29 +02:00
example Added some info about the viewModelTemplateID in the example extension 2024-06-04 17:38:12 +02:00
haveibeenpwned ChangePasswordPlugin also use Have I Been Pwned 2024-04-22 17:38:05 +02:00
ics-viewer Replaced ical.es5.min.cjs with ical.js v2.1.0 for #1745 2024-09-17 20:57:45 +02:00
imap-contacts-suggestions Rename MessageSimple* commands to Message* 2024-03-19 19:49:11 +01:00
kolab Update zh, zh-TW translations 2024-08-15 18:33:40 +08:00
ldap-contacts-suggestions Extensions use \MailSo\Log\Inherit 2024-03-31 21:02:05 +02:00
ldap-identities Changed version to 2.3 2024-02-27 14:30:57 +01:00
ldap-login-mapping Fix extensions with login.credentials hook parameters 2024-09-21 00:01:02 +02:00
ldap-mail-accounts Fix extensions with login.credentials hook parameters 2024-09-21 00:01:02 +02:00
login-autoconfig Improved handling of Internationalized Domain Names in punycode 2024-03-12 16:06:17 +01:00
login-cpanel cPanel use extension login-cpanel instead of login-remote 2024-04-17 01:10:03 +02:00
login-external Resolve #1647 2024-07-01 21:24:21 +02:00
login-external-sso Bugfix: undefined $_POST array key 2022-11-11 17:11:44 +01:00
login-gmail Resolve #1663 2024-07-15 14:42:02 +02:00
login-o365 O365 option to use Azure or Personal accounts #1645 2024-09-29 11:50:00 +02:00
login-oauth2 PHP 8.4: Implicitly nullable parameter declarations deprecated 2024-09-17 15:58:37 +02:00
login-override Fix extensions with login.credentials hook parameters 2024-09-21 00:01:02 +02:00
login-proxyauth-example Example how to use PROXYAUTH 2024-03-12 16:22:28 +01:00
login-register Merge pull request #1528 from hguilbert/patch-19 2024-03-31 04:43:44 +02:00
login-remote Fix extensions with login.credentials hook parameters 2024-09-21 00:01:02 +02:00
login-virtuser Fix extensions with login.credentials hook parameters 2024-09-21 00:01:02 +02:00
mailbox-detect Prevent folder/messages flags conflict by using the right name attributes for Folders 2023-03-13 11:49:40 +01:00
nextcloud v2.38.1 2024-10-08 23:07:58 +02:00
override-smtp-credentials Improved handling of Internationalized Domain Names in punycode 2024-03-12 16:06:17 +01:00
proxy-auth Update instructions for Dovecot 2.4 2025-06-07 13:06:23 +02:00
recaptcha Improved handling of Internationalized Domain Names in punycode 2024-03-12 16:06:17 +01:00
search-filters Set author for #1673 2024-08-06 13:40:43 +02:00
send-save-in v2.38.1 2024-10-08 23:07:58 +02:00
set-remote-addr Resolve #1195 2023-07-03 15:33:38 +02:00
smtp-use-from-adr-account Improved handling of Internationalized Domain Names in punycode 2024-03-12 16:06:17 +01:00
snowfall-on-login-screen Fix snowfall plugin #434 2022-06-13 21:21:51 +02:00
two-factor-auth Update zh.ini 2024-10-14 17:53:38 +03:00
video-on-login-screen add video-on-login-screen plugin 2023-11-09 21:24:48 +01:00
view-ics Improved ical parsing for "view-ics" extension 2024-09-18 00:13:39 +02:00
white-list By default throw AccountNotAllowed as confused in #1478 2024-03-04 10:12:59 +01:00
wysiwyg-example v2.34.0 2024-02-13 13:24:45 +01:00
README.md Changes for #1706 2024-09-21 20:15:14 +02:00

Also see https://github.com/the-djmaze/snappymail/tree/master/plugins/example

PHP

class Plugin extends \RainLoop\Plugins\AbstractPlugin
{
	public function __construct();

	/** Returns static::NAME */
	public function Name(): string;

	/** Returns /README file contents or static::DESCRIPTION */
	public function Description(): string;

	/** When $bLangs is boolean it sets the value, else returns current value */
	public function UseLangs(?bool $bLangs = null): bool;

	/** When true the result is empty string, else the error message */
	public function Supported(): string;

	/** Initialize settings */
	public function Init(): void;

	public function FilterAppDataPluginSection(bool $bAdmin, bool $bAuth, array &$aConfig): void;

	/** Returns array of all plugin Property options for use in Admin -> Extensions -> Plugin cog wheel */
	protected function configMapping(): array;

	/** With this function you hook to an event
	 * $sHookName see chapter "Hooks" below for available names
	 * $sFunctionName the name of a function in this class
	 */
	final protected function addHook(string $sHookName, string $sFunctionName): self;

	final protected function addCss(string $sFile, bool $bAdminScope = false): self;

	final protected function addJs(string $sFile, bool $bAdminScope = false): self;

	final protected function addTemplate(string $sFile, bool $bAdminScope = false): self;

	final protected function addJsonHook(string $sActionName, string $sFunctionName): self;

	/**
	 * You may register your own service actions.
	 * Url is like /?{actionname}/etc.
	 * Predefined actions of \RainLoop\ServiceActions that can't be registered are:
	 * - admin
	 * - AdminAppData
	 * - AppData
	 * - Append
	 * - Backup
	 * - BadBrowser
	 * - CspReport
	 * - Css
	 * - Json
	 * - Lang
	 * - Mailto
	 * - NoCookie
	 * - NoScript
	 * - Ping
	 * - Plugins
	 * - ProxyExternal
	 * - Raw
	 * - Sso
	 * - Upload
	 * - UploadBackground
	 * - UploadContacts
	 */
	final protected function addPartHook(string $sActionName, string $sFunctionName): self

	final public function Config(): \RainLoop\Config\Plugin;
	final public function Manager(): \RainLoop\Plugins\Manager;
	final public function Path(): string;
	final public function ConfigMap(bool $flatten = false): array;

	/**
	 * Returns result of Actions->DefaultResponse($sFunctionName, $mData) or json_encode($mData)
	 */
	final protected function jsonResponse(string $sFunctionName, $mData): mixed;

	final public function jsonParam(string $sKey, $mDefault = null): mixed;

	final public function getUserSettings(): array;

	final public function saveUserSettings(array $aSettings): bool;
}

JavaScript

class PluginPopupView extends rl.pluginPopupView
{
	// Happens when DOM is created
	onBuild(dom) {}

	// Happens before showModal()
	beforeShow(...params) {}
	// Happens after showModal()
	onShow(...params) {}
	// Happens after showModal() animation transitionend
	afterShow() {}

	// Happens when user hits Escape or Close key
	// return false to prevent closing, use close() manually
	onClose() {}
	// Happens before animation transitionend
	onHide() {}
	// Happens after animation transitionend
	afterHide() {}
}

PluginPopupView.showModal();

Hooks

$Plugin->addHook('hook.name', 'functionName');

Login

login.credentials.step-1

params:
	string &$sEmail

Happens in resolveLoginCredentials($sEmail) BEFORE resolving domain name.
This is the pure text from the login screen (DoLogin) or the SSO feature (ServiceSso) received by LoginProcess().
- DoLogin() -> LoginProcess() -> resolveLoginCredentials($sEmail)
- ServiceSso() -> LoginProcess() -> resolveLoginCredentials($sEmail)
So $sEmail can just have the value `test` without a domain.

login.credentials.step-2

params:
	string &$sEmail
	string &$sPassword

Happens in resolveLoginCredentials($sEmail) AFTER resolving domain name.
So $sEmail always has a domain (for example `test` is now `test@example.com`).

login.credentials

params:
	string &$sEmail
	string &$sImapUser
	string &$sPassword
	string &$sSmtpUser

	$sEmail is the domain imap->fixUsername() without shortening.
	$sImapUser is the domain imap->fixUsername() for login into IMAP.
	$sSmtpUser is the domain smtp->fixUsername() for login into SMTP.

login.success

params:
	\RainLoop\Model\MainAccount $oAccount

IMAP

imap.before-connect

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Imap\ImapClient $oImapClient
	\MailSo\Imap\Settings $oSettings

imap.after-connect

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Imap\ImapClient $oImapClient
	\MailSo\Imap\Settings $oSettings

imap.before-login

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Imap\ImapClient $oImapClient
	\MailSo\Imap\Settings $oSettings

imap.after-login

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Imap\ImapClient $oImapClient
	bool $bSuccess
	\MailSo\Imap\Settings $oSettings

imap.message-headers

params:
	array &$aHeaders

Allows you to fetch more MIME headers for messages.

Sieve

sieve.before-connect

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Sieve\SieveClient $oSieveClient
	\MailSo\Sieve\Settings $oSettings

sieve.after-connect

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Sieve\SieveClient $oSieveClient
	\MailSo\Sieve\Settings $oSettings

sieve.before-login

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Sieve\SieveClient $oSieveClient
	\MailSo\Sieve\Settings $oSettings

sieve.after-login

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Sieve\SieveClient $oSieveClient
	bool $bSuccess
	\MailSo\Sieve\Settings $oSettings

SMTP

smtp.before-connect

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Smtp\SmtpClient $oSmtpClient
	\MailSo\Smtp\Settings $oSettings

smtp.after-connect

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Smtp\SmtpClient $oSmtpClient
	\MailSo\Smtp\Settings $oSettings

smtp.before-login

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Smtp\SmtpClient $oSmtpClient
	\MailSo\Smtp\Settings $oSettings

smtp.after-login

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Smtp\SmtpClient $oSmtpClient
	bool $bSuccess
	\MailSo\Smtp\Settings $oSettings

Json service actions

Called by RainLoop\ServiceActions::ServiceJson() {actionname} is one of the RainLoop\Actions::Do{ActionName}(), or an extension action as "Plugin{ActionName}" added with Plugin::addJsonHook() and called in JavaScript using rl.pluginRemoteRequest().

json.before-{actionname}

params: none

json.after-{actionname}

params:
	array &$aResponse

json.action-post-call

Obsolete, use json.after-{actionname}

json.action-pre-call

Obsolete, use json.before-{actionname}

filter.json-response

Obsolete, use json.after-{actionname}

Others

filter.account

params:
	\RainLoop\Model\Account $oAccount

filter.action-params

params:
	string $sMethodName
	array &$aCurrentActionParams

filter.app-data

params:
	bool $bAdmin
	array &$aAppData

filter.application-config

params:
	\RainLoop\Config\Application $oConfig

filter.build-message

params:
	\MailSo\Mime\Message $oMessage

Happens before send/save message

filter.build-read-receipt-message

params:
	\MailSo\Mime\Message $oMessage
	\RainLoop\Model\Account $oAccount

filter.domain

params:
	\RainLoop\Model\Domain $oDomain

filter.fabrica

params:
	string $sName
	mixed &$mResult
	\RainLoop\Model\Account $oAccount

filter.http-paths

params:
	array &$aPaths

filter.language

params:
	string &$sLanguage
	bool $bAdmin

Allows you to set a different language

filter.message-html

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Mime\Message $oMessage
	string &$sTextConverted

Happens before send/save message

filter.message-plain

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Mime\Message $oMessage
	string &$sTextConverted

Happens before send/save message

filter.message-rcpt

Called by DoSendMessage and DoSendReadReceiptMessage
params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Mime\EmailCollection $oRcpt

filter.read-receipt-message-plain

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Mime\Message $oMessage
	string &$sText

filter.result-message

params:
	\MailSo\Mime\Message $oMessage

Happens when reading message

filter.save-message

params:
	\MailSo\Mime\Message $oMessage

Happens before save message

filter.send-message

params:
	\MailSo\Mime\Message $oMessage

Happens before send message

filter.send-message-stream

params:
	\RainLoop\Model\Account $oAccount
	resource &$rMessageStream
	int &$iMessageStreamSize

filter.send-read-receipt-message

params:
	\MailSo\Mime\Message $oMessage
	\RainLoop\Model\Account $oAccount

filter.smtp-from

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Mime\Message $oMessage
	string &$sFrom

filter.smtp-hidden-rcpt

params:
	\RainLoop\Model\Account $oAccount
	\MailSo\Mime\Message $oMessage
	array &$aHiddenRcpt

filter.smtp-message-stream

Called by DoSendMessage and DoSendReadReceiptMessage
params:
	\RainLoop\Model\Account $oAccount
	resource &$rMessageStream
	int &$iMessageStreamSize

filter.upload-response

params:
	array &$aResponse

json.attachments

params:
	\SnappyMail\AttachmentsAction $oData

json.suggestions-input-parameters

params:
	string &$sQuery
	int &$iLimit
	\RainLoop\Model\Account $oAccount

main.content-security-policy

params:
	\SnappyMail\HTTP\CSP $oCSP

Allows you to edit the policy, like:
`$oCSP->script[] = "'strict-dynamic'";`

main.default-response

Obsolete, use json.after-{actionname}

main.default-response-data

Obsolete, use json.after-{actionname}

main.default-response-error-data

Obsolete, use json.after-{actionname}

main.fabrica

params:
	string $sName
	mixed &$mResult

JavaScript Events

mailbox

mailbox.inbox-unread-count

mailbox.message-list.selector.go-up

mailbox.message-list.selector.go-down

mailbox.message.show

Use to show a specific message.
	dispatchEvent(
		new CustomEvent(
			'mailbox.message.show',
			{
				detail: {
					folder: 'INBOX',
					uid: 1
				},
				cancelable: false
			}
		)
	);

audio

audio.start

audio.stop

audio.api.stop

Misc

rl-layout

event.detail value is one of:
0. NoPreview
1. SidePreview
2. BottomPreview

rl-view-model.create

event.detail = the ViewModel class
Happens immediately after the ViewModel constructor.
See accessible properties as https://github.com/the-djmaze/snappymail/blob/master/dev/Knoin/AbstractViews.js

rl-view-model

event.detail = the ViewModel class
Happens after the full build (vm.onBuild()) and contains viewModelDom

rl-vm-visible

event.detail = the ViewModel class
Happens after the model is made visible (vm.afterShow())

sm-admin-login

event.detail = FormData
cancelable using preventDefault()

sm-admin-login-response

event.detail = { error: int, data: {JSON response} }

sm-user-login

event.detail = FormData
cancelable using preventDefault()

sm-user-login-response

event.detail = { error: int, data: {JSON response} }

sm-show-screen

event.detail = 'screenname'
cancelable using preventDefault()

squire-toolbar

event.detail = { squire: SquireUI, actions: object }
`actions` is the toolbar structure.
```javascript
block-of-buttons: {
	button-name: {
		select: ['selectbox options'],
		html: 'button text',
		cmd: () => `command to execute`,
		key: 'keyboard shortcut',
		matches: 'HTML elements that match'
	}
}
```
See [SquireUI.js](https://github.com/the-djmaze/snappymail/blob/master/dev/External/SquireUI.js)
for all default toolbar actions.

JavaScript rl object

rl.Enums.StorageResultType

rl.Enums.StorageResultType.Abort

rl.Enums.StorageResultType.Error

rl.Enums.StorageResultType.Success

rl.​Utils.htmlToPlain(html)

Converts HTML to text

rl.Utils.plainToHtml(plain)

Converts text to HTML

rl.addSettingsViewModel(SettingsViewModelClass, template, labelName, route)​

Examples in

  • ./change-password/js/ChangePasswordUserSettings.js
  • ./example/js/ExampleUserSettings.js
  • ./kolab/js/settings.js
  • ./two-factor-auth/js/TwoFactorAuthSettings.js

rl.addSettingsViewModelForAdmin(SettingsViewModelClass, template, labelName, route)​

Examples in

  • ./example/js/ExampleAdminSettings.js:34: rl.addSettingsViewModelForAdmin(ExampleAdminSettings, 'ExampleAdminSettingsTab',

rl.adminArea()​

Returns true or false when in '?admin' area

rl.app.Remote.abort(action)​​​​​

rl.app.Remote.get(action, url)​​​​​

rl.app.Remote.getPublicKey(fCallback)​​​​​

rl.app.Remote.post(action, fTrigger, params, timeOut)​​​​​

rl.app.Remote.request(action, fCallback, params, iTimeout, sGetAdd)​​​​​

rl.app.Remote.setTrigger(trigger, value)​​​​​

rl.app.Remote.streamPerLine(fCallback, sGetAdd, postData)

rl.app.folderList

A knockout observable array of all folders/mailboxes

rl.fetch(resource, init, postData)​

rl.fetchJSON(resource, init, postData)​

rl.i18n(key, valueList, defaulValue)​

rl.loadScript(src)​

rl.logoutReload(url)​

rl.pluginPopupView

class AbstractViewPopup

rl.pluginRemoteRequest(callback, action, parameters, timeout)​

rl.pluginSettingsGet(pluginSection, name)​

rl.registerWYSIWYG(name, construct)​

rl.route.root()

rl.route.reload()

rl.route.off()

rl.setTitle(title)​

rl.settings.get(name)

rl.settings.set(name, value)

rl.settings.app(name)