Rachel's Yard

| A New Continuation

Yeah.. Unfortunately, Dermail being the side project, it doesn't have a beautiful or convenient installer. You need to setup Dermail manually. But once it is up, assuming that it is setup correctly, it should be the best thing you ever have.

RethinkDB

The main protagonist is the RethinkDB database. Refer to offcial document on how to install on your distro and configurating.

my setup: My (three) RethinkDB instances are running in a private VLAN, and setup up as a cluster (3 replicas, 3 shreds).

Once you have RethinkDB setup, we will create the tables, and setup the components.

Misc

Source Code: https://github.com/zllovesuki/dermail-misc

This is a very simple Express application that will handle link and images sanitization in the mail body.

Configure config.js accordingly. Yes, this requires access to the database.

It is expected to be behind a reverse proxy, like Nginx. You can put Misc on the same machine as Webmail.

Updated: 04/29/2016 - Misc is no longer needed; it is consolidated into a central api

TX

SMTP outbound is actually the easiest part.

Source Code: https://github.com/zllovesuki/dermail-tx

You will need to:

  1. npm install
  2. Put your SSL private key in "ssl/key" and your SSL chain in "ssl/chain", because TX will receive request via HTTP
  3. Change the domain name in app.js. Somehow I hardcoded that, oops.
  4. node cluster.js or forever start cluster.js after the last component

You might want to point a subdomain to this machine. For example, tx-1.email.com, you will need this later.

RX

This is the MDA for Dermail, and this too requires SSL and a domain.

Source Code: https://github.com/zllovesuki/dermail-rx

Configure config.js accordingly. rethinkdb is pretty straightforward. However, basePort is for clustering. Say, 8 instances, then RX will spawn and listen at 8000, 8001, 8002... 8007.

It is expected to be behind a reverse proxy, like Nginx. You can put RX on the same machine as Webmail.

Again,

  1. npm install
  2. node cluster.js or forever start cluster.js after the last component
  3. A subdomain is expected as well. For example. rx-1.email.com, You are gonna need it.

Updated: 04/29/2016 - RX is no longer needed; it is consolidated into a central api

API

After some consideration, why not just combine some elements of Dermail into one central place?

As of 04/29/2016, Misc, RX, and the backend of Webmail are moved into API.

Source Code: https://github.com/zllovesuki/dermail-api

Then, you will need a config.json for sensitive information:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"remoteSecret": "SECRET",
"jwt": "ANOTHER SECRET",
"gcm_api_key": "GCM KEY",
"tx": [{
"priority": 10,
"hook": "https://TX-ENDPOINT/tx-hook"
}],
"s3": {
"endpoint": "S3-ENDPOINT",
"key": "S3-KEY",
"secret": "S3-SECRET",
"bucket": "S3-BUCKET"
},
"rethinkdb": {
"host": "127.0.0.1",
"port": 28015,
"db": "dermail"
},
"redisQ": {
"host": "127.0.0.1",
"port": 6379
}
}

What? Redis? Yes, you need Redis for API. This is the queue for outbound SMTP.

  1. remoteSecret is used to "authenticate" MTA or other components. You will need this again later
  2. jwt is your secret key to encrypt JWT token. Since Webmail is a single page app, it will use JWT for, authentication and authorization. Please, make it safe.
  3. gcm_api_key is your developer API key. You will need it and you will want it for push notification.
  4. tx is your TX endpoint. Change tx to your TX endpoint configured above, or you will not be able to send emails. It is an array of endpoints, so you can have multiple endpoints to avoid single point of failure.
  5. s3 is your S3 information. It can be AWS, it can be on-premise, but you will need a S3 somewhere for your attachments
  6. rethinkdb and redisQ should be straightforward.
  7. Change the S3 URL in api/safe.js, or your attachment links will be incorrect. Sorry about the hardcoded parameters. This is no longer needed.
  8. You then need to generate the app.js for the single-page app. Run npm prod. If you run into problems, most likely it is because of vueify and uglify. Install those two globally.

It is expected to be behind a reverse proxy, like Nginx. If WebSocket doesn't work, make sure that you have:

1
2
3
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;

MTA

Trust me, this is pretty straightforward as well, but it requires a bit more.

Redis

Install Redis as usual on your distro, make sure it only listens on 127.0.0.1

named

By default, your machine will have a nameserver of 8.8.8.8 or some other crap. However, since the MTA uses Spamhaus Zen to detect bad senders, you will need to run your own resolver. MTA will enforce nameserver 127.0.0.1 on startup

Actual MTA

Source Code: https://github.com/zllovesuki/dermail-mta

Configure config.js accordingly. redisQ usually stays the same. Then, you will need a config.json for API:

1
2
3
4
5
6
7
8
{
"redisQ":{
"host": "127.0.0.1",
"port": 6379
},
"remoteSecret": "SECRET",
"apiEndpoint": "https://API"
}

  1. redisQ should be straightforward.
  2. remoteSecret must match the one in API
  3. API is the API endpoint setup earlier. Change API to your API endpoint configured above, or you will not receive emails. IT MUST BE HTTPS

Then,

  1. npm install
  2. Put your SSL private key in "ssl/key" and your SSL chain in "ssl/chain", because MTA will have STARTSSL support
  3. node clusterMTA.js or forever start clusterMTA.js after the last component
  4. node clusterWorker.js or forever start clusterWorker.js after the last component

You will point your domain's MX record to this machine

Webmail

Yeah! The final piece of the puzzles!

Source Code: https://github.com/zllovesuki/dermail-webmail

As usual, do npm install.

Then, you will need a config.json:

1
2
3
4
5
{
"port": 2001,
"apiEndpoint": "API",
"siteURL": "DOMAIN"
}

  1. API is the API endpoint setup earlier. Change API to your API endpoint configured above, or you will not receive emails. IT MUST BE HTTPS
  2. Default port is 2001. Point your reverse proxy to this.
  3. siteURL is where your webmail is accesible. For example, https://dermail.net WITHOUT TRAILING SLASHES
  4. Change the S3 parameters in src/lib/st.js, or your attachment links will be incorrect. Sorry about the hardcoded parameters. This is no longer needed.
  5. Change public/manifest.json for your GCM push notification.
  6. You then need to generate the app.js for the single-page app. Run npm prod. If you run into problems, most likely it is because of vueify and uglify. Install those two globally.

It is expected to be behind a reverse proxy, like Nginx.

DB Scheme (or lack thereof)

Use database.md in the API component to setup the database.

Start the Engine

Now your Dermail should be up and running. For now, you will need to mannually add the first account:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
var config = require(__dirname + "/config.js");
var r = require('rethinkdb');
var reset = false; // DO NOT SET TRUE TO PRODUCTION ENVIRONMENT
r.connect(config.rethinkdb, function(err, conn) {
if (reset) {
r.table('users').delete().run(conn).then(function(deleted) {
r.table('domains').delete().run(conn).then(function(deleted) {
r.table('accounts').delete().run(conn).then(function(deleted) {
r.table('folders').delete().run(conn).then(function(deleted) {
r.table('addresses').delete().run(conn).then(function(deleted) {
actual(conn);
});
});
});
});
});
} else {
actual(conn);
}
});

function handleError(err) {
if (err) console.error(err);
}
var account = 'me';
var domain = 'domain.com'
var fN = 'John';
var lN = 'Doe';

function actual(conn) {
r.table('users').insert({
username: 'JohnDoe',
password: '', // bcrypt salt
firstName: fN,
lastName: lN
}).getField('generated_keys').do(function(keys) {
return keys(0);
}).run(conn).then(function(userId) {
r.table('domains').insert({
userId: userId,
domain: domain,
alias: []
}).getField('generated_keys').do(function(keys) {
return keys(0);
}).run(conn).then(function(domainId) {
r.table('accounts').insert({
userId: userId,
domainId: domainId,
account: account
}).getField('generated_keys').do(function(keys) {
return keys(0);
}).run(conn).then(function(accountId) {
r.table('folders').insert({
accountId: accountId,
parent: null,
displayName: 'Inbox',
description: 'Main Inbox',
mutable: false
}).getField('generated_keys').do(function(keys) {
return keys(0);
}).run(conn).then(function(folderId) {
r.table('addresses').insert({
account: account,
domain: domain,
friendlyName: fN + ' ' + lN,
internalOwner: userId
}).getField('generated_keys').do(function(keys) {
return keys(0);
}).run(conn).then(function(addressId) {
console.log('Account ID: ' + accountId);
console.log('User ID: ' + userId);
console.log('Domain ID: ' + domainId);
console.log('Folder ID: ' + folderId);
console.log('Address ID: ' + addressId);
conn.close();
});
})
})
})
})
}

If there is a problem, please email me at private@sdapi.net

Weightless Theme
Rocking Basscss
RSS