Merge branch 'develop'
This commit is contained in:
commit
6254013067
78
README.md
78
README.md
@ -0,0 +1,78 @@
|
|||||||
|
# Rainbox Email
|
||||||
|
|
||||||
|
Rainbox Email is an ISP-like mail service database manager. It also comes with some built-in authentication provider features such as an integrated LDAP server.
|
||||||
|
|
||||||
|
For now, it only supports MySQL.
|
||||||
|
|
||||||
|
Please feel free to contribute by making issues, bug reports and pull requests.
|
||||||
|
|
||||||
|
## /!\ THIS PROJECT STILL LACKS ESSENTIAL FEATURES SUCH AS: /!\
|
||||||
|
|
||||||
|
- Change password
|
||||||
|
- Password recovery (recovery emails are unused yet)
|
||||||
|
- Quota management
|
||||||
|
- Editable terms of service
|
||||||
|
- Complex permissions system
|
||||||
|
- Redirections (can be manually setup with sql queries)
|
||||||
|
- Probably many others, please make an issue so I can add them to this list
|
||||||
|
|
||||||
|
## How does it work?
|
||||||
|
|
||||||
|
When a user register, they don't immediately get a mailbox. If approval_mode is on, then they have to get approved by an administrator. Then they have to create their first email address which will be their mailbox username.
|
||||||
|
|
||||||
|
Users can only create one email address with their username from public domains (domains set as owned by "Public").
|
||||||
|
|
||||||
|
However, domains can also be owned by a specific user in which case the user owning the domain can create infinite addresses @the-domain.com.
|
||||||
|
|
||||||
|
Note that a user only has one mailbox once they create their first address and cannot have more.
|
||||||
|
|
||||||
|
## Installation instructions & recommendations
|
||||||
|
|
||||||
|
### Requirements
|
||||||
|
|
||||||
|
- mariadb (for the mysql database that will be operated)
|
||||||
|
- redis (cache) (this may go as I think I'm not using it at all, but it won't start without it yet)
|
||||||
|
- A working mail smtp server (to send emails)
|
||||||
|
- git and yarn for updates
|
||||||
|
|
||||||
|
### Instructions
|
||||||
|
|
||||||
|
- Create a user i.e. `rainbox-email` and its home directory i.e. `/home/rainbox-email`
|
||||||
|
- `su rainbox-email` (switch to the new user)
|
||||||
|
- `git clone git@gitlab.com:ArisuOngaku/rainbox.email.git ~/live` (clone Rainbox Email into a new `live` folder)
|
||||||
|
- `cd ~/live`
|
||||||
|
- `yarn install && yarn build`
|
||||||
|
- MySQL
|
||||||
|
- Create a new empty database named as per configuration (default is `rainbox_email`)
|
||||||
|
- Create a new mysql user and give them all permissions on the database (`GRANT ALL PRIVILEGES ON rainbox_email.* TO rainbox_email@localhost IDENTIFIED BY "secret_password";`)
|
||||||
|
- Don't forget to add mysql user and password in `config/local.json5` (see ###Configuration)
|
||||||
|
- Configure mail (required) and redis (if needed)
|
||||||
|
- For a private instance, please don't forget to set `approval_mode` to `true`
|
||||||
|
- Service
|
||||||
|
- Edit [app.service](app.service) as needed, copy to `/etc/systemd/system/rainbox-email.service`
|
||||||
|
- When ready, enable and start the service (`systemctl enable --now rainbox-email`)
|
||||||
|
- Once started, if there were no errors then the database should be created.
|
||||||
|
- To gain administrator rights, register an account and then go back to mysql and run: `UPDATE users SET is_admin=1 WHERE name="your_user_name";`
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Create a `config/local.json5` file and override all wanted parameters. See `config/{default,prouction}.json5` and `node_modules/wms-core/config/{default,production}.json5` for defaults.
|
||||||
|
|
||||||
|
## Postfix and dovecot mysql queries
|
||||||
|
|
||||||
|
### Postfix
|
||||||
|
|
||||||
|
- `virtual_mailbox_domains` => `SELECT 1 FROM mail_domains WHERE name='%s'`
|
||||||
|
- `virtual_mailbox_maps` => `SELECT 1 FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id AND u.main_mail_identity_id=i.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%s'`
|
||||||
|
- `virtual_alias_maps` => `(SELECT redirects_to FROM mail_identities i LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%s' AND redirects_to IS NOT NULL) UNION (SELECT CONCAT(i.name, '@', d.name) FROM users u LEFT JOIN mail_identities i ON i.id=u.main_mail_identity_id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE (SELECT u.id FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%s' AND redirects_to IS NULL LIMIT 1)=u.id AND i.id IS NOT NULL)`
|
||||||
|
- `smtpd_sender_login_maps` => `SELECT CONCAT(i.name, '@', d.name) FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%s'`
|
||||||
|
|
||||||
|
### Dovecot `dovecot-sql.conf.ext`
|
||||||
|
|
||||||
|
Note that the quota is hardcoded in the `user_query` to 5GB, please change as needed.
|
||||||
|
|
||||||
|
- `user_query = SELECT CONCAT(i.name, '@', d.name) as user, CONCAT('*:bytes=', '5368709000') as quota_rule, '/storage1/mail/%d/%n' as home, 1011 as uid, 1012 as gid FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id AND u.main_mail_identity_id=i.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%u'`
|
||||||
|
- `password_query = SELECT password FROM users u LEFT JOIN mail_identities i ON i.user_id=u.id AND u.main_mail_identity_id=i.id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE CONCAT(i.name, '@', d.name)='%u' AND redirects_to IS NULL`
|
||||||
|
- `iterate_query = SELECT CONCAT(i.name, '@', d.name) as user FROM users u LEFT JOIN mail_identities i ON i.id=u.main_mail_identity_id LEFT JOIN mail_domains d ON i.mail_domain_id=d.id WHERE i.id IS NOT NULL`
|
||||||
|
|
||||||
|
It is recommended to set `default_pass_scheme = ARGON2ID`.
|
@ -1,16 +1,17 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=WMS website
|
Description=Rainbox Email website
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=wms
|
User=rainbox-email
|
||||||
Group=wms
|
Group=rainbox-email
|
||||||
WorkingDirectory=/home/wms/live
|
WorkingDirectory=/home/rainbox-email/live
|
||||||
Restart=on-success
|
Restart=on-success
|
||||||
Environment=NODE_ENV=production
|
Environment=NODE_ENV=production
|
||||||
ExecStart=/bin/node .
|
ExecStart=/bin/node .
|
||||||
|
ProtectSystem=yes
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
@ -44,4 +44,26 @@
|
|||||||
magic_link: {
|
magic_link: {
|
||||||
validity_period: 20,
|
validity_period: 20,
|
||||||
},
|
},
|
||||||
|
mail_autoconfig: {
|
||||||
|
main_domain: 'localhost',
|
||||||
|
display_name: 'Rainbox Email',
|
||||||
|
display_name_short: 'Rainbox',
|
||||||
|
username: '%EMAILADDRESS%',
|
||||||
|
auth_method: 'password-cleartext',
|
||||||
|
imap: {
|
||||||
|
server: 'localhost',
|
||||||
|
port: '143',
|
||||||
|
method: 'STARTTLS',
|
||||||
|
},
|
||||||
|
pop3: {
|
||||||
|
server: 'localhost',
|
||||||
|
port: '110',
|
||||||
|
method: 'STARTTLS',
|
||||||
|
},
|
||||||
|
smtp: {
|
||||||
|
server: 'localhost',
|
||||||
|
port: '587',
|
||||||
|
method: 'STARTTLS',
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -15,5 +15,27 @@
|
|||||||
approval_mode: true,
|
approval_mode: true,
|
||||||
magic_link: {
|
magic_link: {
|
||||||
validity_period: 900,
|
validity_period: 900,
|
||||||
}
|
},
|
||||||
|
mail_autoconfig: {
|
||||||
|
main_domain: 'rainbox.email',
|
||||||
|
display_name: 'Rainbox Email',
|
||||||
|
display_name_short: 'Rainbox',
|
||||||
|
username: '%EMAILADDRESS%',
|
||||||
|
auth_method: 'password-cleartext',
|
||||||
|
imap: {
|
||||||
|
server: 'rainbox.email',
|
||||||
|
port: '143',
|
||||||
|
method: 'STARTTLS',
|
||||||
|
},
|
||||||
|
pop3: {
|
||||||
|
server: 'rainbox.email',
|
||||||
|
port: '110',
|
||||||
|
method: 'STARTTLS',
|
||||||
|
},
|
||||||
|
smtp: {
|
||||||
|
server: 'rainbox.email',
|
||||||
|
port: '587',
|
||||||
|
method: 'STARTTLS',
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rainbox.email",
|
"name": "rainbox.email",
|
||||||
"version": "2.0.2",
|
"version": "2.1.0",
|
||||||
"description": "ISP mail provider manager with mysql and integrated LDAP server",
|
"description": "ISP mail provider manager with mysql and integrated LDAP server",
|
||||||
"repository": "https://gitlab.com/ArisuOngaku/rainbox.email",
|
"repository": "https://gitlab.com/ArisuOngaku/rainbox.email",
|
||||||
"author": "Alice Gaudon <alice@gaudon.pro>",
|
"author": "Alice Gaudon <alice@gaudon.pro>",
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import Controller from "wms-core/Controller";
|
import Controller from "wms-core/Controller";
|
||||||
import {Request, Response} from "express";
|
import {Request, Response} from "express";
|
||||||
import MailDomain from "../models/MailDomain";
|
import MailDomain from "../models/MailDomain";
|
||||||
|
import config from "config";
|
||||||
|
|
||||||
export default class MailAutoConfigController extends Controller {
|
export default class MailAutoConfigController extends Controller {
|
||||||
public routes(): void {
|
public routes(): void {
|
||||||
this.get('/.well-known/autoconfig/mail/config-v1.1.xml', this.getAutoConfig, 'mail-auto-config');
|
this.get([
|
||||||
|
'/.well-known/autoconfig/mail/config-v1.1.xml',
|
||||||
|
'/mail/config-v1.1.xml',
|
||||||
|
], this.getAutoConfig, 'mail-auto-config');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,26 +18,26 @@ export default class MailAutoConfigController extends Controller {
|
|||||||
res.contentType('text/xml');
|
res.contentType('text/xml');
|
||||||
const domains = await MailDomain.select().get();
|
const domains = await MailDomain.select().get();
|
||||||
res.render('mail-auto-config.xml.njk', {
|
res.render('mail-auto-config.xml.njk', {
|
||||||
domain: domains[0],
|
host_domain: config.get<string>('mail_autoconfig.main_domain'),
|
||||||
domains: domains,
|
domains: domains.sort((a, b) => a.name && b.name && a.name > b.name ? 1 : -1),
|
||||||
display_name: 'Rainbox Email',
|
display_name: config.get<string>('mail_autoconfig.display_name'),
|
||||||
display_name_short: 'Rainbox',
|
display_name_short: config.get<string>('mail_autoconfig.display_name_short'),
|
||||||
username: '%EMAILADDRESS%',
|
username: config.get<string>('mail_autoconfig.username'),
|
||||||
auth_method: 'password-cleartext',
|
auth_method: config.get<string>('mail_autoconfig.auth_method'),
|
||||||
imap: {
|
imap: {
|
||||||
server: 'rainbox.email',
|
server: config.get<string>('mail_autoconfig.imap.server'),
|
||||||
port: '143',
|
port: config.get<string>('mail_autoconfig.imap.port'),
|
||||||
method: 'STARTTLS',
|
method: config.get<string>('mail_autoconfig.imap.method'),
|
||||||
},
|
},
|
||||||
pop3: {
|
pop3: {
|
||||||
server: 'rainbox.email',
|
server: config.get<string>('mail_autoconfig.pop3.server'),
|
||||||
port: '110',
|
port: config.get<string>('mail_autoconfig.pop3.port'),
|
||||||
method: 'STARTTLS',
|
method: config.get<string>('mail_autoconfig.pop3.method'),
|
||||||
},
|
},
|
||||||
smtp: {
|
smtp: {
|
||||||
server: 'rainbox.email',
|
server: config.get<string>('mail_autoconfig.smtp.server'),
|
||||||
port: '587',
|
port: config.get<string>('mail_autoconfig.smtp.port'),
|
||||||
method: 'STARTTLS',
|
method: config.get<string>('mail_autoconfig.smtp.method'),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<clientConfig version="1.1">
|
<clientConfig version="1.1">
|
||||||
<emailProvider id="{{ domain }}">
|
<emailProvider id="{{ host_domain }}">
|
||||||
<domain>{{ domain }}</domain>
|
{% for domain in domains %}
|
||||||
|
<domain>{{ domain.name }}</domain>
|
||||||
{% for d in domains %}
|
|
||||||
<domain>{{ d.name }}</domain>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
<displayName>{{ display_name }}</displayName>
|
<displayName>{{ display_name }}</displayName>
|
||||||
|
Loading…
Reference in New Issue
Block a user