Skip to content

Commit

Permalink
Added addSyncJobs
Browse files Browse the repository at this point in the history
  • Loading branch information
appcoders committed Aug 14, 2020
1 parent 64a8e24 commit 6cd1055
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Currently there a the following tools:

- [addMailboxes](https://github.com/appcoders/mailcowtools/releases/tag/addmailboxes-1.0.1)
- [updateQuota](https://github.com/appcoders/mailcowtools/releases/tag/updatequota-1.0.0)
- addSyncJobs (soon).
- [addSyncJobs](https://github.com/appcoders/mailcowtools/release/tag/addSyncJobs-1.0.0)

I made them for my own use and maybe they are useful to someone else.

Expand Down
77 changes: 77 additions & 0 deletions addSyncJobs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
## Mailcow - Add Sync Jobs

This tool is made to bulk create mailboxes on mailcow. I made it for my own use and maybe it is useful to someone else.

I am not affiliated with mailcow in any way.

More infos about [mailcow](https://mailcow.email/) and the [mailcow API](https://mx.mailcow.email/api/).
Support mailcow it is great :-) !

### What you need
Just create a CSV file (comma-separated) with three columns eg.

Source IMAP Server mailbox username, Source IMAP Server mailbox password, Mailcow Mailbox name

```
"[email protected]","A-Very-Old-Secret-Password","[email protected]"
"[email protected]""A-Even-More-Old-Secret-Password","[email protected]"
```

You MUST not use a header line.

You need an API key for your mailcow instance.

### Using addSyncJobs
```
Usage: addSyncJobs [options]
Options:
-V, --version output the version number
-i, --syncjobfile <syncjobfile> Path to sync job file CSV
-s, --serverurl <serverurl> URL of mailcow server : https://mailcow.example.org
-a, --apikey <apikey> APIKEY for mailcow API
--host1 <host1> Hostname of IMAP source server
--port1 <port1> Port of IMAP source server (default: "993")
--enc1 <enc1> Encryption mode (PLAIN, SSL, TLS) of IMAP source server (default: "SSL")
--timeout1 <timeout1> Timeout setting in seconds for IMAP source server (default: 600)
--inactive Sync job is added as inactive
--minsinterval <minsinterval> Sync job interval in minutes (default: 20)
--subfolder2 <subfolder2> Sync job target server folder name (default: "")
--maxage <maxage> Syncing only last maxage days (0=syncall) (default: 0)
--maxbytespersecond <maxbytespersecond> Max sync speed in bytes/s (0=no limit) (default: 0)
--delete2duplicates <delete2duplicates> Delete duplicates on target server (1 | 0) (default: 1)
--delete1 Delete messages from source server (1 | 0)
--delete2 Delete messages from target server which are missing on source server (1 | 0)
--automap <automap> Automap target and source folder (1 | 0) (default: 1)
--skipcrossduplicates Skip duplicates over folders first come, first serve
--subscribeall <subscribeall> Subscribe to all folders (default: 1)
--exclude <exclude> Exclude regex elements (default: "(?i)spam|(?i)junk")
--customparams <customparams> Your own imapsync params (default: "")
-e, --exitonerror exit on first error
-h, --help display help for command
```

For example:

```
node addSyncJobs.js -i ./syncjobslist -a XXXXX-ZZZZZZ-TTTTT-YYYYY-SSSSS -e -s https://mailcow.example.com -host1 imap.example.com
```

or if you use [precompiled binaries](https://github.com/appcoders/mailcowtools/releases):

```
addSyncJobs-{version}-{platform} -i ./syncjobslist -a XXXXX-ZZZZZZ-TTTTT-YYYYY-SSSSS -e -s https://mailcow.example.com -host1 imap.example.com
```

Use -e to stop on the first error that occurs.

## Using the source

As usual:
```
yarn install
```

## Pre-built binaries

I build pre-built with [pkg](https://github.com/vercel/pkg#readme) you can also download [here](https://github.com/appcoders/mailcowtools/releases).
143 changes: 143 additions & 0 deletions addSyncJobs/addSyncJobs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Written by Markus Schicker, [email protected]
// MIT License

// Copyright (c) 2020 Markus Schicker

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

const { program } = require('commander');
const axios = require('axios');
const process = require('process');
const csvtojsonV2 = require("csvtojson/v2");
const { exit } = require('process');
const version = require('./package').version;


let axiosInstance = null;

const configureAxios = () => {
const instance = axios.create({
baseURL: program.serverurl,
headers: { 'X-API-Key': program.apikey, 'Content-Type': 'application/json' }
});
return instance;
}

const importSyncJobs = async (filename) => {
let importJSON = null;

const settings = {
"delete2duplicates": program.delete2duplicates ? 1 : 0,
"custom_params": program.customparams,
"mins_interval": program.minsinterval,
"authmech1": "PLAIN",
"port1": program.port1,
"timeout1": program.timeout1,
"skipcrossduplicates": program.skipcrossduplicates ? 1 : 0,
"active": program.inactive ? 0 : 1,
"timeout2": 600,
"authmd51": 0,
"regextrans2": "",
"domain2": "",
"subfolder2": program.subfolder2,
"enc1": program.enc1,
"automap": program.automap,
"subscribeall": program.subscribeall,
"maxage": program.maxage,
"host1": program.host1,
"delete1": program.delete1 ? 1 : 0,
"exclude": program.exclude,
"maxbytespersecond": `${program.maxbytespersecond}`,
"delete2": program.delete2 ? 1 : 0
}

try {
importJSON = await csvtojsonV2({
noheader: true,
headers: ['sourceemail', 'sourcepassword', 'targetmailbox']
}).fromFile(filename);
} catch (error) {
console.error(`Error while import:\n${error}`);
process.exit(-1);
}
return importJSON.map(element => {
return { ...settings, user1: element.sourceemail, username: element.targetmailbox, password1: element.sourcepassword }
});
}

const addSyncJob = async (syncJobInfo) => {
try {
const result = await axiosInstance.post('/api/v1/add/syncjob', syncJobInfo);
if (result.status !== 200 || !result.data || !result.data.type === 'success') {
console.error(`Error while adding syncjob ${syncJobInfo.user1} -> ${syncJobInfo.username}`);
if (program.exitonerror) {
process.exit(3);
}
}
console.log(`Added syncjob ${syncJobInfo.user1} -> ${syncJobInfo.username}`);
} catch (error) {
console.error(`Error while adding syncjob ${syncJobInfo.user1} -> ${syncJobInfo.username}:\n${error}`);
process.exit(2);
}
}

const addSyncJobs = async (syncJobsInfos) => {
console.log(`Beginning adding of ${syncJobsInfos.length} syncjobs`);
syncJobsInfos.map(async (syncJobInfo) => {
await addSyncJob(syncJobInfo);
})
}

const main = async () => {
program.version(version);

program
.requiredOption('-i, --syncjobfile <syncjobfile>', 'Path to sync job file CSV')
.requiredOption('-s, --serverurl <serverurl>', 'URL of mailcow server : https://mailcow.example.org')
.requiredOption('-a, --apikey <apikey>', 'APIKEY for mailcow API')
.requiredOption('--host1 <host1>', 'Hostname of IMAP source server')
.option('--port1 <port1>', 'Port of IMAP source server', '993')
.option('--enc1 <enc1>', 'Encryption mode (PLAIN, SSL, TLS) of IMAP source server', 'SSL')
.option('--timeout1 <timeout1>', 'Timeout setting in seconds for IMAP source server', 600)
.option('--inactive', 'Sync job is added as inactive')
.option('--minsinterval <minsinterval>', 'Sync job interval in minutes', 20)
.option('--subfolder2 <subfolder2>', 'Sync job target server folder name', '')
.option('--maxage <maxage>', 'Syncing only last maxage days (0=syncall)', 0)
.option('--maxbytespersecond <maxbytespersecond>', 'Max sync speed in bytes/s (0=no limit)', 0)
.option('--delete2duplicates <delete2duplicates>', 'Delete duplicates on target server (1 | 0)', 1)
.option('--delete1', 'Delete messages from source server (1 | 0)')
.option('--delete2', 'Delete messages from target server which are missing on source server (1 | 0)')
.option('--automap <automap>', 'Automap target and source folder (1 | 0)', 1)
.option('--skipcrossduplicates', 'Skip duplicates over folders first come, first serve')
.option('--subscribeall <subscribeall>', 'Subscribe to all folders', 1)
.option('--exclude <exclude>', 'Exclude regex elements', '(?i)spam|(?i)junk')
.option('--customparams <customparams>', 'Your own imapsync params', '')
.option('-e, --exitonerror', 'exit on first error');

program.parse(process.argv);

axiosInstance = configureAxios();

const syncJobInfos = await importSyncJobs(program.syncjobfile);
await addSyncJobs(syncJobInfos);
}

main();


11 changes: 11 additions & 0 deletions addSyncJobs/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "mailcowaddsyncjobs",
"version": "1.0.0",
"main": "addSyncJobs.js",
"license": "MIT",
"dependencies": {
"axios": "^0.19.2",
"commander": "^6.0.0",
"csvtojson": "^2.0.10"
}
}
65 changes: 65 additions & 0 deletions addSyncJobs/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


axios@^0.19.2:
version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
dependencies:
follow-redirects "1.5.10"

bluebird@^3.5.1:
version "3.7.2"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==

commander@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-6.0.0.tgz#2b270da94f8fb9014455312f829a1129dbf8887e"
integrity sha512-s7EA+hDtTYNhuXkTlhqew4txMZVdszBmKWSPEMxGr8ru8JXR7bLUFIAtPhcSuFdJQ0ILMxnJi8GkQL0yvDy/YA==

csvtojson@^2.0.10:
version "2.0.10"
resolved "https://registry.yarnpkg.com/csvtojson/-/csvtojson-2.0.10.tgz#11e7242cc630da54efce7958a45f443210357574"
integrity sha512-lUWFxGKyhraKCW8Qghz6Z0f2l/PqB1W3AO0HKJzGIQ5JRSlR651ekJDiGJbBT4sRNNv5ddnSGVEnsxP9XRCVpQ==
dependencies:
bluebird "^3.5.1"
lodash "^4.17.3"
strip-bom "^2.0.0"

debug@=3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
dependencies:
ms "2.0.0"

[email protected]:
version "1.5.10"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
dependencies:
debug "=3.1.0"

is-utf8@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=

lodash@^4.17.3:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==

[email protected]:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=

strip-bom@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
dependencies:
is-utf8 "^0.2.0"

0 comments on commit 6cd1055

Please sign in to comment.