├── .dockerignore
├── .gitignore
├── .gitlab-ci.yml
├── LICENSE
├── Makefile
├── README.md
├── VERSION
├── build.sh
├── config.json.dist
├── docs
├── README.md
├── architecture.md
├── configuration.md
├── development.md
├── faq.md
├── setup.md
└── setup_with_postfix.md
├── email2matrix-server.go
├── email2matrix
├── configuration
│ └── configuration.go
├── container
│ └── container.go
├── matrix
│ ├── email_relayer.go
│ ├── message_generator.go
│ └── message_generator_test.go
├── mime
│ ├── parser.go
│ ├── parser_test.go
│ └── testdata
│ │ ├── geary-plain.txt
│ │ ├── gmail-base64.txt
│ │ └── phpmailer-quoted-printable.txt
├── resolver
│ ├── model.go
│ └── resolver.go
└── smtp
│ └── email2matrix_processor.go
├── etc
├── docker
│ ├── Dockerfile
│ └── README.md
└── services
│ ├── docker-compose.yaml
│ ├── matrix-riot-web
│ ├── config.json
│ └── nginx.conf
│ └── matrix-synapse
│ ├── email2matrix.127.0.0.1.xip.io.log.config
│ ├── email2matrix.127.0.0.1.xip.io.signing.key
│ └── homeserver.yaml
├── go.mod
└── go.sum
/.dockerignore:
--------------------------------------------------------------------------------
1 | /var
2 | /vendor/
3 | /pkg
4 | /email2matrix-server
5 | /config.json
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /var
2 | /vendor
3 | /email2matrix-server
4 | /config.json
5 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | variables:
2 | # We opt for the fastest compression, because our artifacts are bzip2-compressed already.
3 | ARTIFACT_COMPRESSION_LEVEL: "fastest"
4 |
5 | CONTAINER_IMAGE_NAME: devture/email2matrix
6 | CONTAINER_IMAGE_NAME_DASHED: devture-email2matrix
7 |
8 | LATEST_REPOSITORY_BRANCH_NAME: master
9 | LATEST_CONTAINER_IMAGE_TAG_PREFIX: latest
10 |
11 | CONTAINER_REGISTRY: 'docker.io'
12 | CONTAINER_REGISTRY_USER: ''
13 | CONTAINER_REGISTRY_PASSWORD: ''
14 |
15 | # This pipeline is only triggered for tags, the default branch and the `LATEST_REPOSITORY_BRANCH_NAME` branch (which likely matches the default).
16 | # Publishing may follow different rules.
17 | workflow:
18 | rules:
19 | - if: $CI_COMMIT_TAG
20 | - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
21 | - if: $CI_COMMIT_BRANCH == $LATEST_REPOSITORY_BRANCH_NAME
22 |
23 | stages:
24 | - build-container-images
25 | - publish-container-images
26 |
27 | build-container-image-amd64:
28 | extends: .build-container-image
29 | variables:
30 | PLATFORM: linux/amd64
31 | PLATFORM_IDENTIFIER: amd64
32 |
33 | build-container-image-arm64v8:
34 | extends: .build-container-image
35 | variables:
36 | PLATFORM: linux/arm64/v8
37 | PLATFORM_IDENTIFIER: arm64v8
38 |
39 | build-container-image-arm32v7:
40 | extends: .build-container-image
41 | variables:
42 | PLATFORM: linux/arm/v7
43 | PLATFORM_IDENTIFIER: arm32v7
44 |
45 | # This private job spec that we invoke via `build-container-image-*` jobs:
46 | # - builds the container image for the given platform (`PLATFORM`, `PLATFORM_IDENTIFIER`)
47 | # - tags it as `CONTAINER_IMAGE_NAME:CONTAINER_IMAGE_TAG` (`CONTAINER_IMAGE_TAG` is dynamically built below)
48 | # - exports it as an artifact to a file (`${CONTAINER_IMAGE_NAME_DASHED}-${CI_COMMIT_SHORT_SHA}-${PLATFORM_IDENTIFIER}-container-image.tbz2`)
49 | #
50 | # This build job is inspired by: https://medium.com/prgcont/using-buildah-in-gitlab-ci-9b529af19e42
51 | .build-container-image:
52 | stage: build-container-images
53 | needs: []
54 |
55 | image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/tomkukral/buildah:0.30
56 |
57 | before_script:
58 | # Log in to the Gitlab Dependency Proxy container regsitry, so we can use it below.
59 | - podman login ${CI_DEPENDENCY_PROXY_SERVER} -u ${CI_DEPENDENCY_PROXY_USER} -p ${CI_DEPENDENCY_PROXY_PASSWORD}
60 |
61 | # Log in to Docker Hub regardless of whether we'll be pushing images or not, because rate limits for logged in users are higher.
62 | - podman login ${CONTAINER_REGISTRY} -u ${CONTAINER_REGISTRY_USER} -p ${CONTAINER_REGISTRY_PASSWORD}
63 |
64 | - podman run --rm --network=none --privileged ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/multiarch/qemu-user-static --reset -p yes
65 |
66 | - CONTAINER_IMAGE_TAG="${CI_COMMIT_SHORT_SHA}-${PLATFORM_IDENTIFIER}"
67 |
68 | # We might potentially modify the Dockerfile we'll build from (below),
69 | # so we'd like to modify a copy of it, instead of dirtying up the git worktree.
70 | # The reason we care about keeping the git worktree clean is that `govvv` (see the Dockerfile) will say "dirty" if we don't.
71 | - cp etc/docker/Dockerfile /tmp/Dockerfile
72 |
73 | # Use the Gitlab Dependency Proxy instead of docker.io to speed things up and avoid rate limits.
74 | #
75 | # Pulling from Dependency Proxy is only enabled on amd64 for now,
76 | # because using it to pull multiarch images (such as the ones we have in the Dockerfile) causes issues.
77 | # See: https://gitlab.com/gitlab-org/gitlab/-/issues/349466
78 | - |
79 | if [ "$PLATFORM_IDENTIFIER" == "amd64" ]; then
80 | sed --in-place 's|docker.io|'${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}'|g' /tmp/Dockerfile
81 | fi
82 |
83 | script:
84 | - echo Building for ${PLATFORM} and tagging as ${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG}
85 | - buildah bud -f /tmp/Dockerfile --format=docker --platform=${PLATFORM} -t ${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG} .
86 | - podman save ${CONTAINER_IMAGE_NAME}:${CONTAINER_IMAGE_TAG} | bzip2 > ${CONTAINER_IMAGE_NAME_DASHED}-${CI_COMMIT_SHORT_SHA}-${PLATFORM_IDENTIFIER}-container-image.tbz2
87 |
88 | artifacts:
89 | name: ${CONTAINER_IMAGE_NAME_DASHED}-${CI_COMMIT_SHORT_SHA}-${PLATFORM_IDENTIFIER}-container-image.tbz2
90 | paths:
91 | - ${CONTAINER_IMAGE_NAME_DASHED}-${CI_COMMIT_SHORT_SHA}-${PLATFORM_IDENTIFIER}-container-image.tbz2
92 |
93 | # This publishing job:
94 | # - takes all platform-specific images from artifact files
95 | # - imports them all locally
96 | # - re-tags them and publishes to Docker Hub
97 | publish-container-images:
98 | stage: publish-container-images
99 | needs:
100 | - build-container-image-amd64
101 | - build-container-image-arm64v8
102 | - build-container-image-arm32v7
103 | dependencies:
104 | - build-container-image-amd64
105 | - build-container-image-arm64v8
106 | - build-container-image-arm32v7
107 |
108 | image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/tomkukral/buildah:0.30
109 |
110 | before_script:
111 | - |
112 | for platform_identifier in amd64 arm64v8 arm32v7; do
113 | podman load -i "${CONTAINER_IMAGE_NAME_DASHED}-${CI_COMMIT_SHORT_SHA}-${platform_identifier}-container-image.tbz2"
114 | done
115 |
116 | # Repository pushes to `LATEST_REPOSITORY_BRANCH_NAME` will trigger an image push for `image:LATEST` and `image:LATEST-PLATFORM_IDENTIFIER`.
117 | # Repository pushes to a tag (e.g. `VERSION_TAG`) will trigger an image push for `image:VERSION_TAG` and `image:VERSION_TAG-PLATFORM_IDENTIFIER`
118 | - |
119 | container_image_published_tag_prefix=""
120 |
121 | if [ "$CI_COMMIT_BRANCH" == "$LATEST_REPOSITORY_BRANCH_NAME" ]; then
122 | container_image_published_tag_prefix=${LATEST_CONTAINER_IMAGE_TAG_PREFIX}
123 | fi
124 |
125 | if [ "$CI_COMMIT_TAG" ]; then
126 | container_image_published_tag_prefix=${CI_COMMIT_TAG}
127 | fi
128 |
129 | # We push a manifest in the v2s2 format, instead of the default (oci). Otherwise Docker Hub's UI does not render it correctly.
130 | script:
131 | - |
132 | if [ "$container_image_published_tag_prefix" ]; then
133 | podman login ${CONTAINER_REGISTRY} -u ${CONTAINER_REGISTRY_USER} -p ${CONTAINER_REGISTRY_PASSWORD}
134 |
135 | set -x
136 |
137 | for platform_identifier in amd64 arm64v8 arm32v7; do
138 | podman tag ${CONTAINER_IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}-${platform_identifier} ${CONTAINER_REGISTRY}/${CONTAINER_IMAGE_NAME}:${container_image_published_tag_prefix}-${platform_identifier}
139 | podman push ${CONTAINER_REGISTRY}/${CONTAINER_IMAGE_NAME}:${container_image_published_tag_prefix}-${platform_identifier}
140 | done
141 |
142 | podman manifest create ${CONTAINER_REGISTRY}/${CONTAINER_IMAGE_NAME}:${container_image_published_tag_prefix} ${CONTAINER_REGISTRY}/${CONTAINER_IMAGE_NAME}:${container_image_published_tag_prefix}-amd64 ${CONTAINER_REGISTRY}/${CONTAINER_IMAGE_NAME}:${container_image_published_tag_prefix}-arm64v8 ${CONTAINER_REGISTRY}/${CONTAINER_IMAGE_NAME}:${container_image_published_tag_prefix}-arm32v7
143 |
144 | podman manifest push --format=v2s2 ${CONTAINER_REGISTRY}/${CONTAINER_IMAGE_NAME}:${container_image_published_tag_prefix} ${CONTAINER_REGISTRY}/${CONTAINER_IMAGE_NAME}:${container_image_published_tag_prefix}
145 | fi
146 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU AFFERO GENERAL PUBLIC LICENSE
2 | Version 3, 19 November 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU Affero General Public License is a free, copyleft license for
11 | software and other kinds of works, specifically designed to ensure
12 | cooperation with the community in the case of network server software.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | our General Public Licenses are intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users.
19 |
20 | When we speak of free software, we are referring to freedom, not
21 | price. Our General Public Licenses are designed to make sure that you
22 | have the freedom to distribute copies of free software (and charge for
23 | them if you wish), that you receive source code or can get it if you
24 | want it, that you can change the software or use pieces of it in new
25 | free programs, and that you know you can do these things.
26 |
27 | Developers that use our General Public Licenses protect your rights
28 | with two steps: (1) assert copyright on the software, and (2) offer
29 | you this License which gives you legal permission to copy, distribute
30 | and/or modify the software.
31 |
32 | A secondary benefit of defending all users' freedom is that
33 | improvements made in alternate versions of the program, if they
34 | receive widespread use, become available for other developers to
35 | incorporate. Many developers of free software are heartened and
36 | encouraged by the resulting cooperation. However, in the case of
37 | software used on network servers, this result may fail to come about.
38 | The GNU General Public License permits making a modified version and
39 | letting the public access it on a server without ever releasing its
40 | source code to the public.
41 |
42 | The GNU Affero General Public License is designed specifically to
43 | ensure that, in such cases, the modified source code becomes available
44 | to the community. It requires the operator of a network server to
45 | provide the source code of the modified version running there to the
46 | users of that server. Therefore, public use of a modified version, on
47 | a publicly accessible server, gives the public access to the source
48 | code of the modified version.
49 |
50 | An older license, called the Affero General Public License and
51 | published by Affero, was designed to accomplish similar goals. This is
52 | a different license, not a version of the Affero GPL, but Affero has
53 | released a new version of the Affero GPL which permits relicensing under
54 | this license.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | TERMS AND CONDITIONS
60 |
61 | 0. Definitions.
62 |
63 | "This License" refers to version 3 of the GNU Affero General Public License.
64 |
65 | "Copyright" also means copyright-like laws that apply to other kinds of
66 | works, such as semiconductor masks.
67 |
68 | "The Program" refers to any copyrightable work licensed under this
69 | License. Each licensee is addressed as "you". "Licensees" and
70 | "recipients" may be individuals or organizations.
71 |
72 | To "modify" a work means to copy from or adapt all or part of the work
73 | in a fashion requiring copyright permission, other than the making of an
74 | exact copy. The resulting work is called a "modified version" of the
75 | earlier work or a work "based on" the earlier work.
76 |
77 | A "covered work" means either the unmodified Program or a work based
78 | on the Program.
79 |
80 | To "propagate" a work means to do anything with it that, without
81 | permission, would make you directly or secondarily liable for
82 | infringement under applicable copyright law, except executing it on a
83 | computer or modifying a private copy. Propagation includes copying,
84 | distribution (with or without modification), making available to the
85 | public, and in some countries other activities as well.
86 |
87 | To "convey" a work means any kind of propagation that enables other
88 | parties to make or receive copies. Mere interaction with a user through
89 | a computer network, with no transfer of a copy, is not conveying.
90 |
91 | An interactive user interface displays "Appropriate Legal Notices"
92 | to the extent that it includes a convenient and prominently visible
93 | feature that (1) displays an appropriate copyright notice, and (2)
94 | tells the user that there is no warranty for the work (except to the
95 | extent that warranties are provided), that licensees may convey the
96 | work under this License, and how to view a copy of this License. If
97 | the interface presents a list of user commands or options, such as a
98 | menu, a prominent item in the list meets this criterion.
99 |
100 | 1. Source Code.
101 |
102 | The "source code" for a work means the preferred form of the work
103 | for making modifications to it. "Object code" means any non-source
104 | form of a work.
105 |
106 | A "Standard Interface" means an interface that either is an official
107 | standard defined by a recognized standards body, or, in the case of
108 | interfaces specified for a particular programming language, one that
109 | is widely used among developers working in that language.
110 |
111 | The "System Libraries" of an executable work include anything, other
112 | than the work as a whole, that (a) is included in the normal form of
113 | packaging a Major Component, but which is not part of that Major
114 | Component, and (b) serves only to enable use of the work with that
115 | Major Component, or to implement a Standard Interface for which an
116 | implementation is available to the public in source code form. A
117 | "Major Component", in this context, means a major essential component
118 | (kernel, window system, and so on) of the specific operating system
119 | (if any) on which the executable work runs, or a compiler used to
120 | produce the work, or an object code interpreter used to run it.
121 |
122 | The "Corresponding Source" for a work in object code form means all
123 | the source code needed to generate, install, and (for an executable
124 | work) run the object code and to modify the work, including scripts to
125 | control those activities. However, it does not include the work's
126 | System Libraries, or general-purpose tools or generally available free
127 | programs which are used unmodified in performing those activities but
128 | which are not part of the work. For example, Corresponding Source
129 | includes interface definition files associated with source files for
130 | the work, and the source code for shared libraries and dynamically
131 | linked subprograms that the work is specifically designed to require,
132 | such as by intimate data communication or control flow between those
133 | subprograms and other parts of the work.
134 |
135 | The Corresponding Source need not include anything that users
136 | can regenerate automatically from other parts of the Corresponding
137 | Source.
138 |
139 | The Corresponding Source for a work in source code form is that
140 | same work.
141 |
142 | 2. Basic Permissions.
143 |
144 | All rights granted under this License are granted for the term of
145 | copyright on the Program, and are irrevocable provided the stated
146 | conditions are met. This License explicitly affirms your unlimited
147 | permission to run the unmodified Program. The output from running a
148 | covered work is covered by this License only if the output, given its
149 | content, constitutes a covered work. This License acknowledges your
150 | rights of fair use or other equivalent, as provided by copyright law.
151 |
152 | You may make, run and propagate covered works that you do not
153 | convey, without conditions so long as your license otherwise remains
154 | in force. You may convey covered works to others for the sole purpose
155 | of having them make modifications exclusively for you, or provide you
156 | with facilities for running those works, provided that you comply with
157 | the terms of this License in conveying all material for which you do
158 | not control copyright. Those thus making or running the covered works
159 | for you must do so exclusively on your behalf, under your direction
160 | and control, on terms that prohibit them from making any copies of
161 | your copyrighted material outside their relationship with you.
162 |
163 | Conveying under any other circumstances is permitted solely under
164 | the conditions stated below. Sublicensing is not allowed; section 10
165 | makes it unnecessary.
166 |
167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168 |
169 | No covered work shall be deemed part of an effective technological
170 | measure under any applicable law fulfilling obligations under article
171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172 | similar laws prohibiting or restricting circumvention of such
173 | measures.
174 |
175 | When you convey a covered work, you waive any legal power to forbid
176 | circumvention of technological measures to the extent such circumvention
177 | is effected by exercising rights under this License with respect to
178 | the covered work, and you disclaim any intention to limit operation or
179 | modification of the work as a means of enforcing, against the work's
180 | users, your or third parties' legal rights to forbid circumvention of
181 | technological measures.
182 |
183 | 4. Conveying Verbatim Copies.
184 |
185 | You may convey verbatim copies of the Program's source code as you
186 | receive it, in any medium, provided that you conspicuously and
187 | appropriately publish on each copy an appropriate copyright notice;
188 | keep intact all notices stating that this License and any
189 | non-permissive terms added in accord with section 7 apply to the code;
190 | keep intact all notices of the absence of any warranty; and give all
191 | recipients a copy of this License along with the Program.
192 |
193 | You may charge any price or no price for each copy that you convey,
194 | and you may offer support or warranty protection for a fee.
195 |
196 | 5. Conveying Modified Source Versions.
197 |
198 | You may convey a work based on the Program, or the modifications to
199 | produce it from the Program, in the form of source code under the
200 | terms of section 4, provided that you also meet all of these conditions:
201 |
202 | a) The work must carry prominent notices stating that you modified
203 | it, and giving a relevant date.
204 |
205 | b) The work must carry prominent notices stating that it is
206 | released under this License and any conditions added under section
207 | 7. This requirement modifies the requirement in section 4 to
208 | "keep intact all notices".
209 |
210 | c) You must license the entire work, as a whole, under this
211 | License to anyone who comes into possession of a copy. This
212 | License will therefore apply, along with any applicable section 7
213 | additional terms, to the whole of the work, and all its parts,
214 | regardless of how they are packaged. This License gives no
215 | permission to license the work in any other way, but it does not
216 | invalidate such permission if you have separately received it.
217 |
218 | d) If the work has interactive user interfaces, each must display
219 | Appropriate Legal Notices; however, if the Program has interactive
220 | interfaces that do not display Appropriate Legal Notices, your
221 | work need not make them do so.
222 |
223 | A compilation of a covered work with other separate and independent
224 | works, which are not by their nature extensions of the covered work,
225 | and which are not combined with it such as to form a larger program,
226 | in or on a volume of a storage or distribution medium, is called an
227 | "aggregate" if the compilation and its resulting copyright are not
228 | used to limit the access or legal rights of the compilation's users
229 | beyond what the individual works permit. Inclusion of a covered work
230 | in an aggregate does not cause this License to apply to the other
231 | parts of the aggregate.
232 |
233 | 6. Conveying Non-Source Forms.
234 |
235 | You may convey a covered work in object code form under the terms
236 | of sections 4 and 5, provided that you also convey the
237 | machine-readable Corresponding Source under the terms of this License,
238 | in one of these ways:
239 |
240 | a) Convey the object code in, or embodied in, a physical product
241 | (including a physical distribution medium), accompanied by the
242 | Corresponding Source fixed on a durable physical medium
243 | customarily used for software interchange.
244 |
245 | b) Convey the object code in, or embodied in, a physical product
246 | (including a physical distribution medium), accompanied by a
247 | written offer, valid for at least three years and valid for as
248 | long as you offer spare parts or customer support for that product
249 | model, to give anyone who possesses the object code either (1) a
250 | copy of the Corresponding Source for all the software in the
251 | product that is covered by this License, on a durable physical
252 | medium customarily used for software interchange, for a price no
253 | more than your reasonable cost of physically performing this
254 | conveying of source, or (2) access to copy the
255 | Corresponding Source from a network server at no charge.
256 |
257 | c) Convey individual copies of the object code with a copy of the
258 | written offer to provide the Corresponding Source. This
259 | alternative is allowed only occasionally and noncommercially, and
260 | only if you received the object code with such an offer, in accord
261 | with subsection 6b.
262 |
263 | d) Convey the object code by offering access from a designated
264 | place (gratis or for a charge), and offer equivalent access to the
265 | Corresponding Source in the same way through the same place at no
266 | further charge. You need not require recipients to copy the
267 | Corresponding Source along with the object code. If the place to
268 | copy the object code is a network server, the Corresponding Source
269 | may be on a different server (operated by you or a third party)
270 | that supports equivalent copying facilities, provided you maintain
271 | clear directions next to the object code saying where to find the
272 | Corresponding Source. Regardless of what server hosts the
273 | Corresponding Source, you remain obligated to ensure that it is
274 | available for as long as needed to satisfy these requirements.
275 |
276 | e) Convey the object code using peer-to-peer transmission, provided
277 | you inform other peers where the object code and Corresponding
278 | Source of the work are being offered to the general public at no
279 | charge under subsection 6d.
280 |
281 | A separable portion of the object code, whose source code is excluded
282 | from the Corresponding Source as a System Library, need not be
283 | included in conveying the object code work.
284 |
285 | A "User Product" is either (1) a "consumer product", which means any
286 | tangible personal property which is normally used for personal, family,
287 | or household purposes, or (2) anything designed or sold for incorporation
288 | into a dwelling. In determining whether a product is a consumer product,
289 | doubtful cases shall be resolved in favor of coverage. For a particular
290 | product received by a particular user, "normally used" refers to a
291 | typical or common use of that class of product, regardless of the status
292 | of the particular user or of the way in which the particular user
293 | actually uses, or expects or is expected to use, the product. A product
294 | is a consumer product regardless of whether the product has substantial
295 | commercial, industrial or non-consumer uses, unless such uses represent
296 | the only significant mode of use of the product.
297 |
298 | "Installation Information" for a User Product means any methods,
299 | procedures, authorization keys, or other information required to install
300 | and execute modified versions of a covered work in that User Product from
301 | a modified version of its Corresponding Source. The information must
302 | suffice to ensure that the continued functioning of the modified object
303 | code is in no case prevented or interfered with solely because
304 | modification has been made.
305 |
306 | If you convey an object code work under this section in, or with, or
307 | specifically for use in, a User Product, and the conveying occurs as
308 | part of a transaction in which the right of possession and use of the
309 | User Product is transferred to the recipient in perpetuity or for a
310 | fixed term (regardless of how the transaction is characterized), the
311 | Corresponding Source conveyed under this section must be accompanied
312 | by the Installation Information. But this requirement does not apply
313 | if neither you nor any third party retains the ability to install
314 | modified object code on the User Product (for example, the work has
315 | been installed in ROM).
316 |
317 | The requirement to provide Installation Information does not include a
318 | requirement to continue to provide support service, warranty, or updates
319 | for a work that has been modified or installed by the recipient, or for
320 | the User Product in which it has been modified or installed. Access to a
321 | network may be denied when the modification itself materially and
322 | adversely affects the operation of the network or violates the rules and
323 | protocols for communication across the network.
324 |
325 | Corresponding Source conveyed, and Installation Information provided,
326 | in accord with this section must be in a format that is publicly
327 | documented (and with an implementation available to the public in
328 | source code form), and must require no special password or key for
329 | unpacking, reading or copying.
330 |
331 | 7. Additional Terms.
332 |
333 | "Additional permissions" are terms that supplement the terms of this
334 | License by making exceptions from one or more of its conditions.
335 | Additional permissions that are applicable to the entire Program shall
336 | be treated as though they were included in this License, to the extent
337 | that they are valid under applicable law. If additional permissions
338 | apply only to part of the Program, that part may be used separately
339 | under those permissions, but the entire Program remains governed by
340 | this License without regard to the additional permissions.
341 |
342 | When you convey a copy of a covered work, you may at your option
343 | remove any additional permissions from that copy, or from any part of
344 | it. (Additional permissions may be written to require their own
345 | removal in certain cases when you modify the work.) You may place
346 | additional permissions on material, added by you to a covered work,
347 | for which you have or can give appropriate copyright permission.
348 |
349 | Notwithstanding any other provision of this License, for material you
350 | add to a covered work, you may (if authorized by the copyright holders of
351 | that material) supplement the terms of this License with terms:
352 |
353 | a) Disclaiming warranty or limiting liability differently from the
354 | terms of sections 15 and 16 of this License; or
355 |
356 | b) Requiring preservation of specified reasonable legal notices or
357 | author attributions in that material or in the Appropriate Legal
358 | Notices displayed by works containing it; or
359 |
360 | c) Prohibiting misrepresentation of the origin of that material, or
361 | requiring that modified versions of such material be marked in
362 | reasonable ways as different from the original version; or
363 |
364 | d) Limiting the use for publicity purposes of names of licensors or
365 | authors of the material; or
366 |
367 | e) Declining to grant rights under trademark law for use of some
368 | trade names, trademarks, or service marks; or
369 |
370 | f) Requiring indemnification of licensors and authors of that
371 | material by anyone who conveys the material (or modified versions of
372 | it) with contractual assumptions of liability to the recipient, for
373 | any liability that these contractual assumptions directly impose on
374 | those licensors and authors.
375 |
376 | All other non-permissive additional terms are considered "further
377 | restrictions" within the meaning of section 10. If the Program as you
378 | received it, or any part of it, contains a notice stating that it is
379 | governed by this License along with a term that is a further
380 | restriction, you may remove that term. If a license document contains
381 | a further restriction but permits relicensing or conveying under this
382 | License, you may add to a covered work material governed by the terms
383 | of that license document, provided that the further restriction does
384 | not survive such relicensing or conveying.
385 |
386 | If you add terms to a covered work in accord with this section, you
387 | must place, in the relevant source files, a statement of the
388 | additional terms that apply to those files, or a notice indicating
389 | where to find the applicable terms.
390 |
391 | Additional terms, permissive or non-permissive, may be stated in the
392 | form of a separately written license, or stated as exceptions;
393 | the above requirements apply either way.
394 |
395 | 8. Termination.
396 |
397 | You may not propagate or modify a covered work except as expressly
398 | provided under this License. Any attempt otherwise to propagate or
399 | modify it is void, and will automatically terminate your rights under
400 | this License (including any patent licenses granted under the third
401 | paragraph of section 11).
402 |
403 | However, if you cease all violation of this License, then your
404 | license from a particular copyright holder is reinstated (a)
405 | provisionally, unless and until the copyright holder explicitly and
406 | finally terminates your license, and (b) permanently, if the copyright
407 | holder fails to notify you of the violation by some reasonable means
408 | prior to 60 days after the cessation.
409 |
410 | Moreover, your license from a particular copyright holder is
411 | reinstated permanently if the copyright holder notifies you of the
412 | violation by some reasonable means, this is the first time you have
413 | received notice of violation of this License (for any work) from that
414 | copyright holder, and you cure the violation prior to 30 days after
415 | your receipt of the notice.
416 |
417 | Termination of your rights under this section does not terminate the
418 | licenses of parties who have received copies or rights from you under
419 | this License. If your rights have been terminated and not permanently
420 | reinstated, you do not qualify to receive new licenses for the same
421 | material under section 10.
422 |
423 | 9. Acceptance Not Required for Having Copies.
424 |
425 | You are not required to accept this License in order to receive or
426 | run a copy of the Program. Ancillary propagation of a covered work
427 | occurring solely as a consequence of using peer-to-peer transmission
428 | to receive a copy likewise does not require acceptance. However,
429 | nothing other than this License grants you permission to propagate or
430 | modify any covered work. These actions infringe copyright if you do
431 | not accept this License. Therefore, by modifying or propagating a
432 | covered work, you indicate your acceptance of this License to do so.
433 |
434 | 10. Automatic Licensing of Downstream Recipients.
435 |
436 | Each time you convey a covered work, the recipient automatically
437 | receives a license from the original licensors, to run, modify and
438 | propagate that work, subject to this License. You are not responsible
439 | for enforcing compliance by third parties with this License.
440 |
441 | An "entity transaction" is a transaction transferring control of an
442 | organization, or substantially all assets of one, or subdividing an
443 | organization, or merging organizations. If propagation of a covered
444 | work results from an entity transaction, each party to that
445 | transaction who receives a copy of the work also receives whatever
446 | licenses to the work the party's predecessor in interest had or could
447 | give under the previous paragraph, plus a right to possession of the
448 | Corresponding Source of the work from the predecessor in interest, if
449 | the predecessor has it or can get it with reasonable efforts.
450 |
451 | You may not impose any further restrictions on the exercise of the
452 | rights granted or affirmed under this License. For example, you may
453 | not impose a license fee, royalty, or other charge for exercise of
454 | rights granted under this License, and you may not initiate litigation
455 | (including a cross-claim or counterclaim in a lawsuit) alleging that
456 | any patent claim is infringed by making, using, selling, offering for
457 | sale, or importing the Program or any portion of it.
458 |
459 | 11. Patents.
460 |
461 | A "contributor" is a copyright holder who authorizes use under this
462 | License of the Program or a work on which the Program is based. The
463 | work thus licensed is called the contributor's "contributor version".
464 |
465 | A contributor's "essential patent claims" are all patent claims
466 | owned or controlled by the contributor, whether already acquired or
467 | hereafter acquired, that would be infringed by some manner, permitted
468 | by this License, of making, using, or selling its contributor version,
469 | but do not include claims that would be infringed only as a
470 | consequence of further modification of the contributor version. For
471 | purposes of this definition, "control" includes the right to grant
472 | patent sublicenses in a manner consistent with the requirements of
473 | this License.
474 |
475 | Each contributor grants you a non-exclusive, worldwide, royalty-free
476 | patent license under the contributor's essential patent claims, to
477 | make, use, sell, offer for sale, import and otherwise run, modify and
478 | propagate the contents of its contributor version.
479 |
480 | In the following three paragraphs, a "patent license" is any express
481 | agreement or commitment, however denominated, not to enforce a patent
482 | (such as an express permission to practice a patent or covenant not to
483 | sue for patent infringement). To "grant" such a patent license to a
484 | party means to make such an agreement or commitment not to enforce a
485 | patent against the party.
486 |
487 | If you convey a covered work, knowingly relying on a patent license,
488 | and the Corresponding Source of the work is not available for anyone
489 | to copy, free of charge and under the terms of this License, through a
490 | publicly available network server or other readily accessible means,
491 | then you must either (1) cause the Corresponding Source to be so
492 | available, or (2) arrange to deprive yourself of the benefit of the
493 | patent license for this particular work, or (3) arrange, in a manner
494 | consistent with the requirements of this License, to extend the patent
495 | license to downstream recipients. "Knowingly relying" means you have
496 | actual knowledge that, but for the patent license, your conveying the
497 | covered work in a country, or your recipient's use of the covered work
498 | in a country, would infringe one or more identifiable patents in that
499 | country that you have reason to believe are valid.
500 |
501 | If, pursuant to or in connection with a single transaction or
502 | arrangement, you convey, or propagate by procuring conveyance of, a
503 | covered work, and grant a patent license to some of the parties
504 | receiving the covered work authorizing them to use, propagate, modify
505 | or convey a specific copy of the covered work, then the patent license
506 | you grant is automatically extended to all recipients of the covered
507 | work and works based on it.
508 |
509 | A patent license is "discriminatory" if it does not include within
510 | the scope of its coverage, prohibits the exercise of, or is
511 | conditioned on the non-exercise of one or more of the rights that are
512 | specifically granted under this License. You may not convey a covered
513 | work if you are a party to an arrangement with a third party that is
514 | in the business of distributing software, under which you make payment
515 | to the third party based on the extent of your activity of conveying
516 | the work, and under which the third party grants, to any of the
517 | parties who would receive the covered work from you, a discriminatory
518 | patent license (a) in connection with copies of the covered work
519 | conveyed by you (or copies made from those copies), or (b) primarily
520 | for and in connection with specific products or compilations that
521 | contain the covered work, unless you entered into that arrangement,
522 | or that patent license was granted, prior to 28 March 2007.
523 |
524 | Nothing in this License shall be construed as excluding or limiting
525 | any implied license or other defenses to infringement that may
526 | otherwise be available to you under applicable patent law.
527 |
528 | 12. No Surrender of Others' Freedom.
529 |
530 | If conditions are imposed on you (whether by court order, agreement or
531 | otherwise) that contradict the conditions of this License, they do not
532 | excuse you from the conditions of this License. If you cannot convey a
533 | covered work so as to satisfy simultaneously your obligations under this
534 | License and any other pertinent obligations, then as a consequence you may
535 | not convey it at all. For example, if you agree to terms that obligate you
536 | to collect a royalty for further conveying from those to whom you convey
537 | the Program, the only way you could satisfy both those terms and this
538 | License would be to refrain entirely from conveying the Program.
539 |
540 | 13. Remote Network Interaction; Use with the GNU General Public License.
541 |
542 | Notwithstanding any other provision of this License, if you modify the
543 | Program, your modified version must prominently offer all users
544 | interacting with it remotely through a computer network (if your version
545 | supports such interaction) an opportunity to receive the Corresponding
546 | Source of your version by providing access to the Corresponding Source
547 | from a network server at no charge, through some standard or customary
548 | means of facilitating copying of software. This Corresponding Source
549 | shall include the Corresponding Source for any work covered by version 3
550 | of the GNU General Public License that is incorporated pursuant to the
551 | following paragraph.
552 |
553 | Notwithstanding any other provision of this License, you have
554 | permission to link or combine any covered work with a work licensed
555 | under version 3 of the GNU General Public License into a single
556 | combined work, and to convey the resulting work. The terms of this
557 | License will continue to apply to the part which is the covered work,
558 | but the work with which it is combined will remain governed by version
559 | 3 of the GNU General Public License.
560 |
561 | 14. Revised Versions of this License.
562 |
563 | The Free Software Foundation may publish revised and/or new versions of
564 | the GNU Affero General Public License from time to time. Such new versions
565 | will be similar in spirit to the present version, but may differ in detail to
566 | address new problems or concerns.
567 |
568 | Each version is given a distinguishing version number. If the
569 | Program specifies that a certain numbered version of the GNU Affero General
570 | Public License "or any later version" applies to it, you have the
571 | option of following the terms and conditions either of that numbered
572 | version or of any later version published by the Free Software
573 | Foundation. If the Program does not specify a version number of the
574 | GNU Affero General Public License, you may choose any version ever published
575 | by the Free Software Foundation.
576 |
577 | If the Program specifies that a proxy can decide which future
578 | versions of the GNU Affero General Public License can be used, that proxy's
579 | public statement of acceptance of a version permanently authorizes you
580 | to choose that version for the Program.
581 |
582 | Later license versions may give you additional or different
583 | permissions. However, no additional obligations are imposed on any
584 | author or copyright holder as a result of your choosing to follow a
585 | later version.
586 |
587 | 15. Disclaimer of Warranty.
588 |
589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597 |
598 | 16. Limitation of Liability.
599 |
600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608 | SUCH DAMAGES.
609 |
610 | 17. Interpretation of Sections 15 and 16.
611 |
612 | If the disclaimer of warranty and limitation of liability provided
613 | above cannot be given local legal effect according to their terms,
614 | reviewing courts shall apply local law that most closely approximates
615 | an absolute waiver of all civil liability in connection with the
616 | Program, unless a warranty or assumption of liability accompanies a
617 | copy of the Program in return for a fee.
618 |
619 | END OF TERMS AND CONDITIONS
620 |
621 | How to Apply These Terms to Your New Programs
622 |
623 | If you develop a new program, and you want it to be of the greatest
624 | possible use to the public, the best way to achieve this is to make it
625 | free software which everyone can redistribute and change under these terms.
626 |
627 | To do so, attach the following notices to the program. It is safest
628 | to attach them to the start of each source file to most effectively
629 | state the exclusion of warranty; and each file should have at least
630 | the "copyright" line and a pointer to where the full notice is found.
631 |
632 |
633 | Copyright (C)
634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | help: ## Show this help.
2 | @fgrep -h "##" $(MAKEFILE_LIST) | fgrep -v fgrep | sed -e 's/\\$$//' | sed -e 's/##//'
3 |
4 | _prepare_services: var/.env
5 | mkdir -p var/matrix-synapse-media-store var/matrix-synapse-postgres
6 |
7 | var/.env:
8 | mkdir -p var
9 | echo 'CURRENT_USER_UID='`id -u` > var/.env;
10 | echo 'CURRENT_USER_GID='`id -g` >> var/.env
11 |
12 | services-start: _prepare_services ## Starts all services (Postgres, Synapse, Riot)
13 | docker-compose --project-directory var -f etc/services/docker-compose.yaml -p email2matrix up -d
14 |
15 | services-stop: _prepare_services ## Stops all services (Postgres, Synapse, Riot)
16 | docker-compose --project-directory var -f etc/services/docker-compose.yaml -p email2matrix down
17 |
18 | services-tail-logs: _prepare_services ## Tails the logs for all running services
19 | docker-compose --project-directory var -f etc/services/docker-compose.yaml -p email2matrix logs -f
20 |
21 | create-sample-receiver-user: _prepare_services ## Creates a receiver user
22 | docker-compose --project-directory var -f etc/services/docker-compose.yaml -p email2matrix \
23 | exec synapse \
24 | register_new_matrix_user \
25 | -a \
26 | -u receiver \
27 | -p password \
28 | -c /data/homeserver.yaml \
29 | http://localhost:8008
30 |
31 | create-sample-sender-user: _prepare_services ## Creates a sender user
32 | docker-compose --project-directory var -f etc/services/docker-compose.yaml -p email2matrix \
33 | exec synapse \
34 | register_new_matrix_user \
35 | -a \
36 | -u sender \
37 | -p password \
38 | -c /data/homeserver.yaml \
39 | http://localhost:8008
40 |
41 | obtain-sample-sender-access-token: _prepare_services ## Obtain an access token for the sender user
42 | docker run \
43 | -it \
44 | --rm \
45 | --network=email2matrix_default \
46 | alpine:3.10 \
47 | /bin/sh -c "apk add --no-cache curl && curl --data '{\"identifier\": {\"type\": \"m.id.user\", \"user\": \"sender\" }, \"password\": \"password\", \"type\": \"m.login.password\", \"device_id\": \"Sender\", \"initial_device_display_name\": \"Sender\"}' http://synapse:8008/_matrix/client/r0/login"
48 |
49 | run-locally: build-locally ## Builds and runs email2matrix-server locally (no containers)
50 | ./email2matrix-server
51 |
52 | build-locally: ## Builds the email2matrix-server code locally (no containers)
53 | go get -u -v github.com/ahmetb/govvv
54 | rm -f email2matrix-server
55 | go build -a -ldflags "`~/go/bin/govvv -flags`" email2matrix-server.go
56 |
57 | test: ## Runs the tests locally (no containers)
58 | go test ./...
59 |
60 | build-container-image: ## Builds a Docker container image
61 | docker build -t devture/email2matrix:latest -f etc/docker/Dockerfile .
62 |
63 | run-in-container: build-container-image ## Runs email2matrix in a container
64 | docker run \
65 | -it \
66 | --rm \
67 | --name=email2matrix \
68 | -p 40025:2525 \
69 | --mount type=bind,src=`pwd`/config.json,dst=/config.json,ro \
70 | --network=email2matrix_default \
71 | devture/email2matrix:latest
72 |
73 | send-sample-email-to-test-mailbox: ## Sends a sample email to email2matrix
74 | docker run \
75 | -it \
76 | --rm \
77 | --network=email2matrix_default \
78 | alpine:3.10 \
79 | /bin/sh -c "apk add --no-cache ssmtp && sed -i s/mailhub=mail/mailhub=email2matrix:2525/ /etc/ssmtp/ssmtp.conf && echo -e \"Subject: this is the subject\n\nthis is the body\" | ssmtp test@email2matrix.127.0.0.1.xip.io"
80 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Email2Matrix: SMTP server relaying messages to Matrix rooms
2 |
3 | ---------------------------------------
4 |
5 | ⚠️ **Warning**: This application is outdated and no longer maintained. We recommend that you use [postmoogle](https://github.com/etkecc/postmoogle) instead.
6 |
7 | ---------------------------------------
8 |
9 | [email2matrix](https://github.com/devture/email2matrix) is an SMTP server (powered by [Go-Guerrilla](https://github.com/flashmob/go-guerrilla)), which receives messages to certain special (predefined) mailboxes and relays them to [Matrix](http://matrix.org/) rooms.
10 |
11 | This is useful when you've got a system which is capable of sending email (notifications, reminders, etc.) and you'd like for that system to actually send a Matrix message instead.
12 |
13 | Instead of redoing such systems (adding support for sending messages over the [Matrix](https://matrix.org) protocol to each one), you can just configure them to send emails to the Email2Matrix server and have those email messages relayed over to Matrix.
14 |
15 | To learn more, refer to the [Documentation](./docs/README.md).
16 |
17 |
18 | ## Support
19 |
20 | Matrix room: [#email2matrix:devture.com](https://matrix.to/#/#email2matrix:devture.com)
21 |
22 | Github issues: [devture/email2matrix/issues](https://github.com/devture/email2matrix/issues)
23 |
--------------------------------------------------------------------------------
/VERSION:
--------------------------------------------------------------------------------
1 | 1.1.0
2 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | rm -f ${PWD}/email2matrix-server
4 |
5 | docker run --rm -ti \
6 | -v ${PWD}:/work \
7 | -w /work \
8 | golang:1.12.7-buster \
9 | sh -c 'go get -u -v github.com/ahmetb/govvv && go build -a -ldflags "$(govvv -flags)" email2matrix-server.go'
10 |
--------------------------------------------------------------------------------
/config.json.dist:
--------------------------------------------------------------------------------
1 | {
2 | "Smtp": {
3 | "ListenInterface": "0.0.0.0:2525",
4 | "Hostname": "email2matrix.127.0.0.1.xip.io",
5 | "Workers": 10
6 | },
7 | "Matrix": {
8 | "Mappings": [
9 | {
10 | "MailboxName": "test",
11 | "MatrixRoomId": "!ABCD:email2matrix.127.0.0.1.xip.io",
12 | "MatrixHomeserverUrl": "http://synapse:8008",
13 | "MatrixUserId": "@sender:email2matrix.127.0.0.1.xip.io",
14 | "MatrixAccessToken": "TOKEN_GOES_HERE",
15 | "IgnoreSubject": false,
16 | "IgnoreBody": false,
17 | "SkipMarkdown": false
18 | }
19 | ]
20 | },
21 | "Misc": {
22 | "Debug": true
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Email2Matrix documentation
2 |
3 | Email2Matrix forwards emails as [Matrix](http://matrix.org/) messages according to a [configuration policy](configuration.md).
4 |
5 |
6 | ## Table of Contents
7 |
8 | - Learning
9 |
10 | - [Architecture](architecture.md)
11 |
12 | - [FAQ](faq.md)
13 |
14 | - [Configuration](configuration.md)
15 | - [Setup](setup.md)
16 | - [Running on the same host with postfix](setup_with_postfix.md)
17 | - [Development](development.md)
18 |
--------------------------------------------------------------------------------
/docs/architecture.md:
--------------------------------------------------------------------------------
1 | # Architecture
2 |
3 |
4 | ```
5 | Email sending system
6 | |
7 | |
8 | | +---------------------+ +----------------------+
9 | | | | | |
10 | | SMTP 25 | Email2Matrix | HTTPS (client API) | Matrix Homeserver |
11 | +--------> | | ------------------> | (e.g. Synapse) |
12 | | | | |
13 | +---------------------+ +----------------------+
14 | ```
15 |
16 | Things to note:
17 |
18 | - `email2matrix` receives email messages sent from another system
19 |
20 | - the mailbox that a message gets delivered to (e.g. `mailbox5@email2matrix.example.com`) designates where the message will be forwarded to on the Matrix side (such mappings are defined in `config.json` manually)
21 |
22 | - `email2matrix` then uses the [Matrix Client-Server API](https://matrix.org/docs/spec/client_server/r0.5.0) with a pre-created user and access token in order to send a Matrix message to a specific room (as defined in `config.json`)
23 |
--------------------------------------------------------------------------------
/docs/configuration.md:
--------------------------------------------------------------------------------
1 | # Email2Matrix Configuration
2 |
3 | The `email2matrix` server configuration is a JSON document that looks like this:
4 |
5 | ```json
6 | {
7 | "Smtp": {
8 | "ListenInterface": "0.0.0.0:25",
9 | "Hostname": "email2matrix.example.com",
10 | "Workers": 10
11 | },
12 | "Matrix": {
13 | "Mappings": [
14 | {
15 | "MailboxName": "test",
16 | "MatrixRoomId": "!ABCD:example.com",
17 | "MatrixHomeserverUrl": "https://matrix.example.com",
18 | "MatrixUserId": "@svc.test.sender:example.com",
19 | "MatrixAccessToken": "TOKEN_GOES_HERE",
20 | "IgnoreSubject": false,
21 | "IgnoreBody": false,
22 | "SkipMarkdown": false
23 | }
24 | ]
25 | },
26 | "Misc": {
27 | "Debug": true
28 | }
29 | }
30 |
31 | ```
32 |
33 | ## Fields
34 |
35 | The configuration contains the following fields:
36 |
37 | - `Smtp` - SMTP server related configuration
38 |
39 | - `ListenInterface` - the network address and port to listen on. If you're running this inside a container, use something like `0.0.0.0:25` (or `0.0.0.0:2525` with `docker run -p 25:2525 ...`).
40 |
41 | - `Hostname` - the hostname of this email server
42 |
43 | - `Workers` - the number of workers to run. Controls how many messages can be received simultaneously.
44 |
45 |
46 | - `Matrix` - Matrix-related configuration
47 |
48 | - `Mappings` - a list of mappings specifying messages going to which mailbox should get sent to which Matrix room, using what kind of credentials, etc.
49 |
50 | - `MailboxName` - the mailbox name (e.g. `mailbox5`). Its full email address would be `MailboxName@Hostname` (`Hostname` is the `Smtp.Hostname` configuration value). All emails received to this mailbox will be forwarded to Matrix. Use a long and ungueassable name for the mailbox to prevent needless spam.
51 |
52 | - `MatrixRoomId` - the Matrix room id where messages should be sent
53 |
54 | - `MatrixHomeserverUrl` - the homeserver through which to send Matrix messages
55 |
56 | - `MatrixUserId` - the full user id through which the Matrix messages would be sent
57 |
58 | - `MatrixAccessToken` - a Matrix access token corresponding to the sender Matrix user (`MatrixUserId`)
59 |
60 | - `IgnoreSubject` - (`true` or `false`) specifies whether the subject should be forwarded to Matrix
61 |
62 | - `IgnoreBody` - (`true` or `false`) specifies whether the message body should be forwarded to Matrix
63 |
64 | - `SkipMarkdown` - (`true` or `false`) specifies whether to send a plain text message or a Markdown (actually HTML) message to Matrix
65 |
66 | - `Misc` - miscellaneous configuration
67 |
68 | - `Debug` - whether to enable debug mode or not (enable for more verbose logs)
69 |
--------------------------------------------------------------------------------
/docs/development.md:
--------------------------------------------------------------------------------
1 | # Development / Experimenting
2 |
3 | If you'd like to contribute code to this project or give it a try locally (before deploying it), you need to:
4 |
5 | - clone this repository
6 |
7 | - get [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/) -- used for running a local Matrix Synapse + riot-web setup, for testing
8 |
9 | - start all dependency services (Postgres, Matrix Synapse, riot-web): `make services-start`. You can stop them later with `make services-stop` or tail their logs with `make services-tail-logs`
10 |
11 | - create a sample "sender" user: `make create-sample-sender-user`
12 |
13 | - create a sample "receiver" user: `make create-sample-receiver-user`
14 |
15 | - you should now be able to log in with user `receiver` and password `password` to the [riot-web instance](http://email2matrix.127.0.0.1.xip.io:41465)
16 |
17 | - using riot-web, from that receiver (`receiver`) user: create a room or two with the `sender` user (full Matrix user id is: `@sender:email2matrix.127.0.0.1.xip.io`)
18 |
19 | - in another browser session (new container tab, private tab, another browser, etc.), log in to [riot-web](http://email2matrix.127.0.0.1.xip.io:41465) with user `sender` and password `password` and accept those room invitations
20 |
21 | - copy the sample configuration: `cp config.json.dist config.json`
22 |
23 | - obtain an access token for the `sender` user using `make obtain-sample-sender-access-token`. You will need the value of the `access_token` field below
24 |
25 | - create a new mapping in `config.json` (see the [Configuration documentation](configuration.md))
26 |
27 | Example:
28 | ```json
29 | {
30 | "Mappings": [
31 | {
32 | "MailboxName": "test",
33 | "MatrixRoomId": "!ROOM_ID_HERE:email2matrix.127.0.0.1.xip.io",
34 | "MatrixHomeserverUrl": "http://synapse:8008",
35 | "MatrixUserId": "@sender:email2matrix.127.0.0.1.xip.io",
36 | "MatrixAccessToken": "SENDER_ACCESS_TOKEN_HERE",
37 | "IgnoreSubject": false,
38 | "IgnoreBody": false,
39 | "SkipMarkdown": false
40 | }
41 | ]
42 | }
43 | ```
44 |
45 | - build and run the `email2matrix` program by executing: `make run-in-container`
46 |
47 | - send a test email by executing: `make send-sample-email-to-test-mailbox`
48 |
49 | - you should now see that email message relayed to the Matrix room created above
50 |
51 |
52 | For local development, it's best to install a [Go](https://golang.org/) compiler (version 1.12 or later is required) locally.
53 | Some tests are available and can be executed with: `make test`.
54 |
--------------------------------------------------------------------------------
/docs/faq.md:
--------------------------------------------------------------------------------
1 | # FAQ
2 |
3 | ## What is Email2Matrix?
4 |
5 | Email2Matrix is an SMTP email server program, which receives messages to special predefined mailboxes (in your `config.json` [configuration file](./configuration.md)) and forwards those messages to rooms over the [Matrix](https://matrix.org) protocol.
6 |
7 |
8 | ## When do I need Email2Matrix?
9 |
10 | You need Email2Matrix when you've got a system which is capable of sending email (notifications, reminders, etc.) and you'd like for that system to actually send a Matrix message instead.
11 |
12 | Instead of redoing such systems (adding support for sending messages over the [Matrix](https://matrix.org) protocol to each one), you can just configure them to send emails to the Email2Matrix server and have those email messages relayed over to Matrix.
13 |
14 |
15 | ## Do I need to use a specific homeserver for this to work?
16 |
17 | No. You can send via any homeserver to any room, even across federation.
18 |
19 |
20 | ## Why do I need to create rooms, access tokens, etc., manually?
21 |
22 | This is built in the simplest way possible.
23 | You need to do more manual work, so that Email2Matrix doesn't and can be kept simple.
24 |
25 | A more easy to use version can be created.
26 | One which acts as a bot, auto-accepts room invitations, manages mailbox mappings in a database, etc., but that hasn't been done yet.
27 |
28 |
29 | ## Do I need special DNS configuration to use this?
30 |
31 | Not necessarily.
32 |
33 | You can use `MX` DNS records if you wish, but you can avoid it as well.
34 |
35 | If you're hosting Email2Matrix on another server which already has a DNS mapping for its hostname, you can [Configure](configuration.md) your `Smtp.Hostname` to match the hostname of the machine (example: `matrix.example.com`).
36 |
37 | On the other hand, if you'd like to have more indirection, feel free to use `MX` DNS records.
38 |
39 | ## Can I run email2matrix on the same host with postfix?
40 |
41 | Yes. Here is the [documentation describing that](setup_with_postfix.md).
42 |
--------------------------------------------------------------------------------
/docs/setup.md:
--------------------------------------------------------------------------------
1 | # Email2Matrix Setup
2 |
3 | The easiest way to run Email2Matrix is using a [Docker](https://www.docker.com/) (or other) container.
4 |
5 | If your Matrix server is installed using [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy), it's easiest if you refer to [the playbook's setup instructions for Email2Matrix](https://github.com/spantaleev/matrix-docker-ansible-deploy/blob/master/docs/configuring-playbook-email2matrix.md) instead of following these.
6 |
7 |
8 | ## Prerequisites
9 |
10 | - [Docker](https://www.docker.com/) or other (e.g. [Podman](https://podman.io/)) container runtime engine
11 |
12 | - **port 25 available** on the host machine where you'd like to run this. If not available, you may also be able to make your existing email server on port 25 relay messages to Email2Matrix running on another port (e.g. 2525), but that's a more complicated setup. A simplified documentation can be found [here](setup_with_postfix.md)
13 |
14 | - Matrix server configuration:
15 |
16 | - you would most likely wish to create one or more dedicated users that would be doing the sending (e.g. `@email2matrix:DOMAIN`)
17 |
18 | - for each of those sender users, you would need to obtain a Matrix Access Token manually. This can happen with a command like this:
19 |
20 | ```
21 | curl \
22 | --data '{"identifier": {"type": "m.id.user", "user": "email2matrix" }, "password": "MATRIX_PASSWORD_FOR_THE_USER", "type": "m.login.password", "device_id": "Email2Matrix", "initial_device_display_name": "Email2Matrix"}' \
23 | https://matrix.DOMAIN/_matrix/client/r0/login
24 | ```
25 |
26 | - A configuration file (`config.json`) created as shown in the [Configuration](configuration.md) documentation page
27 |
28 | - `Smtp.Hostname` in your configuration file should either match the hostname leading to your server (using a regular `A` record), or it should be an MX record that eventually leads to your server. In any case, what you see in `Smtp.Hostname` is the domain that needs to be in the `to` field of the emails you would be sending
29 |
30 | - some mappings need to be defined (mailbox names and where those mailboxes lead on the Matrix side)
31 |
32 |
33 | ## Running
34 |
35 | ```
36 | docker run \
37 | -it \
38 | --rm \
39 | --name=email2matrix \
40 | -p 25:2525 \
41 | --mount type=bind,src=/path/to/your/config.json,dst=/config.json,ro \
42 | --network=email2matrix_default \
43 | devture/email2matrix:latest
44 | ```
45 |
46 | It's better to use a specific Docker image tag (not `:latest`).
47 |
--------------------------------------------------------------------------------
/docs/setup_with_postfix.md:
--------------------------------------------------------------------------------
1 | # Running email2matrix on the same host as postfix
2 |
3 | It's possible to run email2matrix on the same host with postfix. email2matrix can run on a loopback interface and postfix will forward the messges to email2matrix.
4 | This is a simple example what needs to be configured on email2matrix and postfix side to work together on one host.
5 |
6 | ## Architecture
7 |
8 | ```
9 | Email sending system
10 | |
11 | |
12 | | +--------------------+
13 | | SMTP 25 | |
14 | +--------> | Postfix |
15 | | | |
16 | | .......|.......... | +----------------------+
17 | | | | | |
18 | | V | HTTPS (client API) | Matrix Homeserver |
19 | | email2matrix | ------------------> | (e.g. Synapse) |
20 | | | | |
21 | +--------------------+ +----------------------+
22 | ```
23 |
24 | ## Configuration
25 |
26 | ## email2maitrix
27 |
28 | Make sure you run email2matrix on a unused port. For example on port 2525. You can even run it on a lookback interface.
29 |
30 | Example config (partly):
31 | ```
32 | {
33 | "Smtp": {
34 | "ListenInterface": "127.0.0.1:2525",
35 | "Hostname": "email2matrix.example.com",
36 | "Workers": 10
37 | },
38 | "Matrix": ...
39 | ```
40 |
41 | ## Postfix
42 |
43 | * Postfix needs to know that he is responsible for the domain
44 | * main.cf: `mydestination = email2matrix.example.com, localhost`
45 | * Set the transport maps on the destination domain
46 | * main.cf: `transport_maps = hash:/etc/postfix/transport`
47 | * transport `email2matrix.example.com smtp:127.0.0.1:2525`
48 | * create lookup db from plain file `postmap transport` (this creates transport.db)
49 | * Restart postfix
50 | * Look at `/var/log/mail.log` for errors
51 |
--------------------------------------------------------------------------------
/email2matrix-server.go:
--------------------------------------------------------------------------------
1 | // email2matrix is an Email (SMTP) server relaying received messages to a Matrix room.
2 | // Copyright (C) 2019 Slavi Pantaleev
3 | //
4 | // https://devture.com/
5 | //
6 | // This program is free software: you can redistribute it and/or modify
7 | // it under the terms of the GNU Affero General Public License as published
8 | // by the Free Software Foundation, either version 3 of the License, or
9 | // (at your option) any later version.
10 | //
11 | // This program is distributed in the hope that it will be useful,
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | // GNU Affero General Public License for more details.
15 | //
16 | // You should have received a copy of the GNU Affero General Public License
17 | // along with this program. If not, see .
18 |
19 | package main
20 |
21 | import (
22 | "devture-email2matrix/email2matrix/configuration"
23 | "devture-email2matrix/email2matrix/container"
24 | "flag"
25 | "os"
26 | "os/signal"
27 | "syscall"
28 | "fmt"
29 |
30 | guerrilla "github.com/flashmob/go-guerrilla"
31 | log "github.com/sirupsen/logrus"
32 | )
33 |
34 | // Following variables will be statically linked at the time of compiling
35 | // Source: https://oddcode.daveamit.com/2018/08/17/embed-versioning-information-in-golang-binary/
36 |
37 | // GitCommit holds short commit hash of source tree
38 | var GitCommit string
39 |
40 | // GitBranch holds current branch name the code is built off
41 | var GitBranch string
42 |
43 | // GitState shows whether there are uncommitted changes
44 | var GitState string
45 |
46 | // GitSummary holds output of git describe --tags --dirty --always
47 | var GitSummary string
48 |
49 | // BuildDate holds RFC3339 formatted UTC date (build time)
50 | var BuildDate string
51 |
52 | // Version holds contents of ./VERSION file, if exists, or the value passed via the -version option
53 | var Version string
54 |
55 | func main() {
56 | fmt.Printf(`
57 | _ _ ___ _ _
58 | (_) |__ \ | | (_)
59 | ___ _ __ ___ __ _ _| | ) |_ __ ___ __ _| |_ _ __ ___ __
60 | / _ \ '_ ' _ \ / _' | | | / /| '_ ' _ \ / _' | __| '__| \ \/ /
61 | | __/ | | | | | (_| | | |/ /_| | | | | | (_| | |_| | | |> <
62 | \___|_| |_| |_|\__,_|_|_|____|_| |_| |_|\__,_|\__|_| |_/_/\_\
63 | ----------------------------------------------[ Version: %s ]
64 | GitCommit: %s
65 | GitBranch: %s
66 | GitState: %s
67 | GitSummary: %s
68 | BuildDate: %s
69 |
70 | `, Version, GitCommit, GitBranch, GitState, GitSummary, BuildDate)
71 | configPath := flag.String("config", "config.json", "configuration file to use")
72 | flag.Parse()
73 |
74 | configuration, err := configuration.LoadConfiguration(*configPath)
75 | if err != nil {
76 | panic(err)
77 | }
78 |
79 | container, shutdownHandler := container.BuildContainer(*configuration)
80 |
81 | d := container.Get("smtp.server").(guerrilla.Daemon)
82 | err = d.Start()
83 | if err != nil {
84 | log.Panic("start error", err)
85 | }
86 |
87 | channelComplete := make(chan bool)
88 | setupSignalHandling(
89 | channelComplete,
90 | shutdownHandler,
91 | )
92 |
93 | <-channelComplete
94 | }
95 |
96 | func setupSignalHandling(
97 | channelComplete chan bool,
98 | shutdownHandler *container.ContainerShutdownHandler,
99 | ) {
100 | signalChannel := make(chan os.Signal, 2)
101 | signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
102 | go func() {
103 | <-signalChannel
104 |
105 | shutdownHandler.Shutdown()
106 |
107 | channelComplete <- true
108 | }()
109 | }
110 |
--------------------------------------------------------------------------------
/email2matrix/configuration/configuration.go:
--------------------------------------------------------------------------------
1 | package configuration
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "os"
7 | )
8 |
9 | type Configuration struct {
10 | Smtp ConfigurationSmtp
11 | Misc ConfigurationMisc
12 | Matrix ConfigurationMatrix
13 | }
14 |
15 | type ConfigurationSmtp struct {
16 | ListenInterface string
17 | Hostname string
18 | Workers int
19 | }
20 |
21 | type ConfigurationMatrix struct {
22 | Mappings []ConfigurationMatrixMapping
23 | }
24 |
25 | type ConfigurationMatrixMapping struct {
26 | MailboxName string
27 | MatrixRoomId string
28 | MatrixHomeserverUrl string
29 | MatrixUserId string
30 | MatrixAccessToken string
31 | IgnoreSubject bool
32 | IgnoreBody bool
33 | SkipMarkdown bool
34 | }
35 |
36 | type ConfigurationMisc struct {
37 | Debug bool
38 | }
39 |
40 | func LoadConfiguration(filePath string) (*Configuration, error) {
41 | file, err := os.Open(filePath)
42 | if err != nil {
43 | return nil, err
44 | }
45 |
46 | decoder := json.NewDecoder(file)
47 | configuration := Configuration{}
48 | err = decoder.Decode(&configuration)
49 | if err != nil {
50 | return nil, err
51 | }
52 |
53 | if len(configuration.Matrix.Mappings) == 0 {
54 | return nil, fmt.Errorf("There should be at least one entry in Matrix.Mappings")
55 | }
56 |
57 | return &configuration, nil
58 | }
59 |
--------------------------------------------------------------------------------
/email2matrix/container/container.go:
--------------------------------------------------------------------------------
1 | package container
2 |
3 | import (
4 | "devture-email2matrix/email2matrix/configuration"
5 | "devture-email2matrix/email2matrix/resolver"
6 | "devture-email2matrix/email2matrix/smtp"
7 | "fmt"
8 |
9 | "github.com/euskadi31/go-service"
10 | guerrilla "github.com/flashmob/go-guerrilla"
11 | "github.com/flashmob/go-guerrilla/backends"
12 | "github.com/sirupsen/logrus"
13 | )
14 |
15 | type ContainerShutdownHandler struct {
16 | destructors []func()
17 | }
18 |
19 | func (me *ContainerShutdownHandler) Add(destructor func()) {
20 | me.destructors = append(me.destructors, destructor)
21 | }
22 |
23 | func (me *ContainerShutdownHandler) Shutdown() {
24 | for i, _ := range me.destructors {
25 | me.destructors[len(me.destructors)-i-1]()
26 | }
27 | }
28 |
29 | func BuildContainer(
30 | configuration configuration.Configuration,
31 | ) (service.Container, *ContainerShutdownHandler) {
32 | container := service.New()
33 | shutdownHandler := &ContainerShutdownHandler{}
34 |
35 | // The logger is very crucial, so we're defining it outside
36 | logger := logrus.New()
37 | if configuration.Misc.Debug {
38 | logger.Level = logrus.DebugLevel
39 | }
40 |
41 | container.Set("logger", func(c service.Container) interface{} {
42 | return logger
43 | })
44 |
45 | container.Set("resolver", func(c service.Container) interface{} {
46 | return resolver.NewConfigurationBackedMailboxMappingInfoProvider(configuration.Matrix.Mappings)
47 | })
48 |
49 | container.Set("smtp.processor.email2matrix", func(c service.Container) interface{} {
50 | return smtp.Email2MatrixProcessor(logger, c.Get("resolver").(resolver.MailboxMappingInfoProvider))
51 | })
52 |
53 | container.Set("smtp.server", func(c service.Container) interface{} {
54 | cfg := &guerrilla.AppConfig{
55 | AllowedHosts: []string{configuration.Smtp.Hostname},
56 | }
57 |
58 | if configuration.Misc.Debug {
59 | cfg.LogLevel = "debug"
60 | } else {
61 | cfg.LogLevel = "info"
62 | }
63 |
64 | sc := guerrilla.ServerConfig{
65 | ListenInterface: configuration.Smtp.ListenInterface,
66 | IsEnabled: true,
67 | }
68 | cfg.Servers = append(cfg.Servers, sc)
69 |
70 | additionalSaveProcess := ""
71 | if configuration.Misc.Debug {
72 | additionalSaveProcess = "|Debugger"
73 | }
74 | bcfg := backends.BackendConfig{
75 | "save_workers_size": configuration.Smtp.Workers,
76 | "save_process": fmt.Sprintf("HeadersParser|Header|Hasher%s|Email2Matrix", additionalSaveProcess),
77 | "log_received_mails": true,
78 | }
79 | cfg.BackendConfig = bcfg
80 |
81 | d := guerrilla.Daemon{Config: cfg}
82 |
83 | d.AddProcessor("Email2Matrix", c.Get("smtp.processor.email2matrix").(backends.ProcessorConstructor))
84 |
85 | shutdownHandler.Add(func() {
86 | logger.Debug("Shutdown SMTP server")
87 | d.Shutdown()
88 | })
89 |
90 | return d
91 | })
92 |
93 | return container, shutdownHandler
94 | }
95 |
--------------------------------------------------------------------------------
/email2matrix/matrix/email_relayer.go:
--------------------------------------------------------------------------------
1 | package matrix
2 |
3 | import (
4 | "devture-email2matrix/email2matrix/mime"
5 | "devture-email2matrix/email2matrix/resolver"
6 | "errors"
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/matrix-org/gomatrix"
11 | blackfriday "gopkg.in/russross/blackfriday.v2"
12 |
13 | "github.com/flashmob/go-guerrilla/mail"
14 | )
15 |
16 | func Relay(envelope *mail.Envelope, mappingInfo resolver.MailboxMappingInfo) (string, error) {
17 | subject, body, err := mime.ExtractContentFromEmail(envelope.NewReader())
18 | if err != nil {
19 | return "", fmt.Errorf("Failed to parse email: %s", err)
20 | }
21 |
22 | messagePlainOrMarkdown := GenerateMessage(
23 | subject,
24 | body,
25 | mappingInfo.IgnoreSubject,
26 | mappingInfo.IgnoreBody,
27 | mappingInfo.SkipMarkdown,
28 | )
29 |
30 | if messagePlainOrMarkdown == "" {
31 | return "", fmt.Errorf("Refusing to send an empty message")
32 | }
33 |
34 | client, err := gomatrix.NewClient(mappingInfo.MatrixHomeserverUrl, mappingInfo.MatrixUserId, mappingInfo.MatrixAccessToken)
35 | if err != nil {
36 | return "", err
37 | }
38 |
39 | var event *gomatrix.RespSendEvent
40 | if mappingInfo.SkipMarkdown {
41 | event, err = client.SendText(mappingInfo.MatrixRoomId, messagePlainOrMarkdown)
42 | } else {
43 | messageAsHtml := string(blackfriday.Run([]byte(messagePlainOrMarkdown)))
44 |
45 | event, err = client.SendMessageEvent(mappingInfo.MatrixRoomId, "m.room.message", gomatrix.HTMLMessage{
46 | Body: messagePlainOrMarkdown,
47 | MsgType: "m.text",
48 | Format: "org.matrix.custom.html",
49 | FormattedBody: messageAsHtml,
50 | })
51 | }
52 |
53 | if err != nil {
54 | errMessage := strings.Replace(err.Error(), mappingInfo.MatrixAccessToken, "REDACTED", -1)
55 | return "", errors.New(errMessage)
56 | }
57 |
58 | return event.EventID, nil
59 | }
60 |
--------------------------------------------------------------------------------
/email2matrix/matrix/message_generator.go:
--------------------------------------------------------------------------------
1 | package matrix
2 |
3 | import "fmt"
4 |
5 | func GenerateMessage(
6 | subject string,
7 | body string,
8 | ignoreSubject, ignoreBody, skipMarkdown bool,
9 | ) string {
10 | if skipMarkdown {
11 | if ignoreBody || body == "" {
12 | if subject == "" {
13 | return ""
14 | }
15 | return fmt.Sprintf("%s", subject)
16 | }
17 |
18 | if ignoreSubject || subject == "" {
19 | return body
20 | }
21 |
22 | return fmt.Sprintf("%s\n\n%s", subject, body)
23 | }
24 |
25 | if ignoreBody || body == "" {
26 | if subject == "" {
27 | return ""
28 | }
29 | return fmt.Sprintf("# %s", subject)
30 | }
31 |
32 | if ignoreSubject || subject == "" {
33 | return body
34 | }
35 |
36 | return fmt.Sprintf("# %s\n\n%s", subject, body)
37 | }
38 |
--------------------------------------------------------------------------------
/email2matrix/matrix/message_generator_test.go:
--------------------------------------------------------------------------------
1 | package matrix
2 |
3 | import (
4 | "fmt"
5 | "testing"
6 | )
7 |
8 | type testData struct {
9 | subject string
10 | body string
11 |
12 | ignoreSubject bool
13 | ignoreBody bool
14 | skipMarkdown bool
15 |
16 | expectedOutput string
17 | }
18 |
19 | func TestGenerate(t *testing.T) {
20 | tests := []testData{
21 | testData{
22 | subject: "test",
23 | body: "content",
24 | ignoreSubject: false,
25 | ignoreBody: false,
26 | skipMarkdown: false,
27 | expectedOutput: "# test\n\ncontent",
28 | },
29 | testData{
30 | subject: "test",
31 | body: "",
32 | ignoreSubject: false,
33 | ignoreBody: false,
34 | skipMarkdown: false,
35 | expectedOutput: "# test",
36 | },
37 | testData{
38 | subject: "test",
39 | body: "content",
40 | ignoreSubject: false,
41 | ignoreBody: true,
42 | skipMarkdown: false,
43 | expectedOutput: "# test",
44 | },
45 | testData{
46 | subject: "test",
47 | body: "content",
48 | ignoreSubject: false,
49 | ignoreBody: true,
50 | skipMarkdown: true,
51 | expectedOutput: "test",
52 | },
53 | testData{
54 | subject: "test",
55 | body: "content",
56 | ignoreSubject: true,
57 | ignoreBody: false,
58 | skipMarkdown: false,
59 | expectedOutput: "content",
60 | },
61 | testData{
62 | subject: "test",
63 | body: "content",
64 | ignoreSubject: true,
65 | ignoreBody: false,
66 | skipMarkdown: true,
67 | expectedOutput: "content",
68 | },
69 | testData{
70 | subject: "test",
71 | body: "content",
72 | ignoreSubject: false,
73 | ignoreBody: false,
74 | skipMarkdown: true,
75 | expectedOutput: "test\n\ncontent",
76 | },
77 | }
78 |
79 | for idx, test := range tests {
80 | test := test // capture range variable
81 |
82 | t.Run(fmt.Sprintf("test-%d", idx), func(t *testing.T) {
83 | t.Parallel()
84 |
85 | output := GenerateMessage(test.subject, test.body, test.ignoreSubject, test.ignoreBody, test.skipMarkdown)
86 |
87 | if output != test.expectedOutput {
88 | t.Errorf("Expected output `%s`, but got `%s`", test.expectedOutput, output)
89 | return
90 | }
91 | })
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/email2matrix/mime/parser.go:
--------------------------------------------------------------------------------
1 | package mime
2 |
3 | import (
4 | "io"
5 | "strings"
6 |
7 | "github.com/jhillyerd/enmime"
8 | )
9 |
10 | func ExtractContentFromEmail(reader io.Reader) ( /*subject*/ string /*body*/, string, error) {
11 | envelope, err := enmime.ReadEnvelope(reader)
12 | if err != nil {
13 | return "", "", err
14 | }
15 |
16 | subject := envelope.GetHeader("Subject")
17 | body := strings.TrimSpace(envelope.Text)
18 | return subject, body, nil
19 | }
20 |
--------------------------------------------------------------------------------
/email2matrix/mime/parser_test.go:
--------------------------------------------------------------------------------
1 | package mime
2 |
3 | import (
4 | "os"
5 | "testing"
6 | )
7 |
8 | type TestData struct {
9 | filePath string
10 | expectedSubject string
11 | expectedContent string
12 | }
13 |
14 | func TestParser(t *testing.T) {
15 | tests := []TestData{
16 | TestData{
17 | filePath: "./testdata/phpmailer-quoted-printable.txt",
18 | expectedSubject: "Reminder from example.com",
19 | expectedContent: "Тест",
20 | },
21 | TestData{
22 | filePath: "./testdata/geary-plain.txt",
23 | expectedSubject: "some test",
24 | expectedContent: "test",
25 | },
26 | TestData{
27 | filePath: "./testdata/gmail-base64.txt",
28 | expectedSubject: "тест от gmail",
29 | expectedContent: "тест от gmail",
30 | },
31 | }
32 |
33 | for _, test := range tests {
34 | test := test // capture range variable
35 |
36 | t.Run(test.filePath, func(t *testing.T) {
37 | t.Parallel()
38 |
39 | f, err := os.Open(test.filePath)
40 | if err != nil {
41 | t.Errorf("Failed to open file: %s: %s", test.filePath, err)
42 | return
43 | }
44 | defer f.Close()
45 |
46 | subject, content, err := ExtractContentFromEmail(f)
47 | if err != nil {
48 | t.Error(err)
49 | return
50 | }
51 |
52 | if subject != test.expectedSubject {
53 | t.Errorf("Expected subject `%s`, but got `%s`", test.expectedSubject, subject)
54 | return
55 | }
56 |
57 | if content != test.expectedContent {
58 | t.Errorf("Expected content `%s`, but got `%s`", test.expectedContent, content)
59 | return
60 | }
61 | })
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/email2matrix/mime/testdata/geary-plain.txt:
--------------------------------------------------------------------------------
1 | Date: Mon, 01 Jan 2018 15:20:14 +0200
2 | From: Slavi Pantaleev
3 | Subject: some test
4 | To: something@another
5 | Message-Id: <1514812814.31047.2@whatever>
6 | X-Mailer: geary/0.12-dev
7 | MIME-Version: 1.0
8 | Content-Type: multipart/alternative; boundary="=-euby2brpLBXRGzTY2+7t"
9 |
10 | --=-euby2brpLBXRGzTY2+7t
11 | Content-Type: text/plain; charset=us-ascii; format=flowed
12 |
13 | test
14 |
15 | --=-euby2brpLBXRGzTY2+7t
16 | Content-Type: text/html; charset=us-ascii
17 |
18 |
19 | --=-euby2brpLBXRGzTY2+7t--
20 |
--------------------------------------------------------------------------------
/email2matrix/mime/testdata/gmail-base64.txt:
--------------------------------------------------------------------------------
1 | Received: by mail-ua0-f182.google.com with SMTP id a25so27075635uak.3
2 | for ; Tue, 02 Jan 2018 02:31:31 -0800 (PST)
3 | DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
4 | d=gmail.com; s=20161025;
5 | h=mime-version:from:date:message-id:subject:to;
6 | bh=HdjriWLjqV+NydQqVN3sfYBjHdmOr6jUVApAjJui/l0=;
7 | b=lJPrOS23KxW/2jK0IbA6lXtaWV3mDYDl7qvsE1CBFoVhtqXyPtGdEH38bKyY2ycSab
8 | +6ApFY8dij8/0XORPZrfWKfLz3ylVorEUw047NKPKf1UmyLoc4vCj2HzcV/orINtW6IJ
9 | hnv9cw55Wp9sQHEPVy1hvBT42baI3c4PU2JJUv6wkXK6XgoskVfV5EFZwGlPYOifuU46
10 | of1FDqO4OfV19qxstS4pNtEAJ/dBCBzbHbq3XUo820yf0n+LODy59tGknxDeQ3PuiVSX
11 | 5Cf6bWeZj8nSPz9AiDemRcqheR7q22Y+RpBqY1/a2vWFoJNWDWnAKIoEKP2zuel/UIQA
12 | 0T9A==
13 | X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
14 | d=1e100.net; s=20161025;
15 | h=x-gm-message-state:mime-version:from:date:message-id:subject:to;
16 | bh=HdjriWLjqV+NydQqVN3sfYBjHdmOr6jUVApAjJui/l0=;
17 | b=C8r4xqQ8CvQcNHkoag7Kw2TAnnbdhaUIKmkXo6x0B8fdZ3bU0Hzwrx4sbYCL89ekdi
18 | v/k+R9l6GGJQuKdnv31ZDi+4OuQFWxtK3A10hNIcv88slSfsL6mBzgbUISM8KmWDSH7w
19 | R251a01e3vbe+FBVGwmlqjAcA+rd3NAPTOxHnsYgoXhbtO5hLlQ7znzSpqqnrWErYLSL
20 | QeSCVa1ZMs146c7Nh82Dh3bArpJ1JKO0r2pxvEJH+4N+/9poFqq89kP9/SQeAv9HlzAN
21 | UTdqptHZm6ZhzcLqrNjwR8KOrfdoJCnO1bN1v5rBD4RbfgGdW1FCz+3Ci2ZOCHM4G0fh
22 | ICBw==
23 | X-Gm-Message-State: AKGB3mJErtbNN2iOzJG3clIj5rfKAF09PWgqeLpeROzmUsXiMmw8YFo9
24 | xq8O4YFJOAfEyV5N6rhQFcKdjcDlW1Bw6en6wH3weA==
25 | X-Google-Smtp-Source: ACJfBou2gAw7kHabK6TfRiSUqvVyphcL9EEP4Wib+GGKnpApmUfsxO6eJTaKVwcWdXt3OLFiqBV91xNT9XOtSfJFb3o=
26 | X-Received: by 10.176.22.139 with SMTP id e11mr1487238uaf.44.1514889091008;
27 | Tue, 02 Jan 2018 02:31:31 -0800 (PST)
28 | MIME-Version: 1.0
29 | Received: by 10.176.29.23 with HTTP; Tue, 2 Jan 2018 02:31:30 -0800 (PST)
30 | From: Someone
31 | Date: Tue, 2 Jan 2018 12:31:30 +0200
32 | Message-ID:
33 | Subject: =?UTF-8?B?0YLQtdGB0YIg0L7RgiBnbWFpbA==?=
34 | To: something@whatever
35 | Content-Type: multipart/alternative; boundary="f403045f85ee24cc720561c89a52"
36 |
37 | --f403045f85ee24cc720561c89a52
38 | Content-Type: text/plain; charset="UTF-8"
39 | Content-Transfer-Encoding: base64
40 |
41 | 0YLQtdGB0YIg0L7RgiBnbWFpbA0K
42 | --f403045f85ee24cc720561c89a52
43 | Content-Type: text/html; charset="UTF-8"
44 | Content-Transfer-Encoding: base64
45 |
46 | PGRpdiBkaXI9Imx0ciI+0YLQtdGB0YIg0L7RgiBnbWFpbDxicj48L2Rpdj4NCg==
47 | --f403045f85ee24cc720561c89a52--
48 |
--------------------------------------------------------------------------------
/email2matrix/mime/testdata/phpmailer-quoted-printable.txt:
--------------------------------------------------------------------------------
1 | Received: from localhost.localdomain (localhost [IPv6:::1])
2 | by example.com (Postfix) with ESMTP id 393A2600D1
3 | for ; Mon, 1 Jan 2018 17:40:02 +0000 (UTC)
4 | Date: Mon, 1 Jan 2018 17:40:02 +0000
5 | To: slavi
6 | From: Reminders sender
7 | Subject: Reminder from example.com
8 | Message-ID: <7f90123dd371040cafb37be91086b558@localhost.localdomain>
9 | X-Priority: 3
10 | X-Mailer: PHPMailer 5.1 (phpmailer.sourceforge.net)
11 | MIME-Version: 1.0
12 | Content-Type: text/plain; charset="utf-8"
13 | Content-Transfer-Encoding: quoted-printable
14 |
15 | =D0=A2=D0=B5=D1=81=D1=82
16 |
--------------------------------------------------------------------------------
/email2matrix/resolver/model.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | type MailboxMappingInfoProvider interface {
4 | Resolve(mailboxName string) *MailboxMappingInfo
5 | }
6 |
7 | type MailboxMappingInfo struct {
8 | MailboxName string
9 | MatrixHomeserverUrl string
10 | MatrixRoomId string
11 | MatrixUserId string
12 | MatrixAccessToken string
13 | IgnoreSubject bool
14 | IgnoreBody bool
15 | SkipMarkdown bool
16 | }
17 |
--------------------------------------------------------------------------------
/email2matrix/resolver/resolver.go:
--------------------------------------------------------------------------------
1 | package resolver
2 |
3 | import (
4 | "devture-email2matrix/email2matrix/configuration"
5 | )
6 |
7 | type ConfigurationBackedMailboxMappingInfoProvider struct {
8 | mappings []configuration.ConfigurationMatrixMapping
9 | }
10 |
11 | func NewConfigurationBackedMailboxMappingInfoProvider(mappings []configuration.ConfigurationMatrixMapping) *ConfigurationBackedMailboxMappingInfoProvider {
12 | return &ConfigurationBackedMailboxMappingInfoProvider{
13 | mappings: mappings,
14 | }
15 | }
16 |
17 | func (me *ConfigurationBackedMailboxMappingInfoProvider) Resolve(mailboxName string) *MailboxMappingInfo {
18 | for _, item := range me.mappings {
19 | if item.MailboxName == mailboxName {
20 | return &MailboxMappingInfo{
21 | MailboxName: item.MailboxName,
22 | MatrixHomeserverUrl: item.MatrixHomeserverUrl,
23 | MatrixRoomId: item.MatrixRoomId,
24 | MatrixUserId: item.MatrixUserId,
25 | MatrixAccessToken: item.MatrixAccessToken,
26 | IgnoreSubject: item.IgnoreSubject,
27 | IgnoreBody: item.IgnoreBody,
28 | SkipMarkdown: item.SkipMarkdown,
29 | }
30 | }
31 | }
32 |
33 | return nil
34 | }
35 |
--------------------------------------------------------------------------------
/email2matrix/smtp/email2matrix_processor.go:
--------------------------------------------------------------------------------
1 | package smtp
2 |
3 | import (
4 | "devture-email2matrix/email2matrix/matrix"
5 | "devture-email2matrix/email2matrix/resolver"
6 | "errors"
7 | "fmt"
8 |
9 | "github.com/sirupsen/logrus"
10 | "github.com/flashmob/go-guerrilla/backends"
11 | "github.com/flashmob/go-guerrilla/mail"
12 | )
13 |
14 | var Email2MatrixProcessor = func(
15 | logger *logrus.Logger,
16 | resolver resolver.MailboxMappingInfoProvider,
17 | ) backends.ProcessorConstructor {
18 | return func() backends.Decorator {
19 | return func(p backends.Processor) backends.Processor {
20 | return backends.ProcessWith(
21 | func(e *mail.Envelope, task backends.SelectTask) (backends.Result, error) {
22 | if task == backends.TaskSaveMail {
23 | receiverMailbox := e.RcptTo[len(e.RcptTo)-1]
24 |
25 | mappingInfo := resolver.Resolve(receiverMailbox.User)
26 | if mappingInfo == nil {
27 | err := errors.New("Cannot find user")
28 | return backends.NewResult(fmt.Sprintf("450 Error: %s", err)), err
29 | }
30 |
31 | matrixEventId, err := matrix.Relay(e, *mappingInfo)
32 | if err != nil {
33 | return backends.NewResult(fmt.Sprintf("554 Error: %s", err)), err
34 | }
35 |
36 | logger.WithFields(logrus.Fields{
37 | "emailId": e.QueuedId,
38 | "matrixRoomId": mappingInfo.MatrixRoomId,
39 | "matrixEventId": matrixEventId,
40 | }).Infoln("Delivered")
41 |
42 | return p.Process(e, task)
43 | }
44 | return p.Process(e, task)
45 | },
46 | )
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/etc/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM docker.io/golang:1.19.0-alpine3.16
2 | WORKDIR /build
3 | RUN apk --no-cache add git
4 | RUN go install github.com/ahmetb/govvv@v0.3.0
5 | COPY . /build/.
6 | RUN CGO_ENABLED=0 go build -a -installsuffix cgo -ldflags "$(govvv -flags)" email2matrix-server.go
7 |
8 | FROM docker.io/alpine:3.16.1
9 | WORKDIR /
10 | RUN apk --no-cache add ca-certificates
11 | COPY --from=0 /build/email2matrix-server .
12 | CMD ["./email2matrix-server"]
13 |
--------------------------------------------------------------------------------
/etc/docker/README.md:
--------------------------------------------------------------------------------
1 | # Email2Matrix: SMTP server relaying messages to Matrix rooms
2 |
3 | [email2matrix](https://github.com/devture/email2matrix) is an SMTP server (powered by [Go-Guerrilla](https://github.com/flashmob/go-guerrilla)), which receives messages to certain special (predefined) mailboxes and relays them to [Matrix](http://matrix.org/) rooms.
4 |
5 |
6 | # Using this Docker image
7 |
8 | Start off by [creating your configuration](https://github.com/devture/email2matrix/blob/master/docs/configuration.md).
9 |
10 | Since you're running this in a container, make sure `ListenInterface` configuration uses the `0.0.0.0` interface.
11 |
12 | To start the container:
13 |
14 | ```bash
15 | docker run \
16 | -it \
17 | --rm \
18 | -p 127.0.0.1:41080:41080 \
19 | -v /local/path/to/config.json:/config.json:ro \
20 | devture/email2matrix:latest
21 | ```
22 |
23 | **Hint**: using a tagged/versioned image, instead of `latest` is recommended.
24 |
--------------------------------------------------------------------------------
/etc/services/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | version: '2.1'
2 |
3 | services:
4 | postgres:
5 | image: postgres:11.5-alpine
6 | user: ${CURRENT_USER_UID}:${CURRENT_USER_GID}
7 | environment:
8 | POSTGRES_USER: synapse
9 | POSTGRES_PASSWORD: synapse-password
10 | POSTGRES_DB: homeserver
11 | volumes:
12 | - ./matrix-synapse-postgres:/var/lib/postgresql/data
13 | - /etc/passwd:/etc/passwd:ro
14 |
15 | synapse:
16 | image: matrixdotorg/synapse:v1.3.1
17 | user: ${CURRENT_USER_UID}:${CURRENT_USER_GID}
18 | entrypoint: python
19 | command: "-m synapse.app.homeserver -c /data/homeserver.yaml"
20 | restart: on-failure
21 | ports:
22 | # This server does not federate, so we don't expose any more ports.
23 | - "41408:8008"
24 | links:
25 | - postgres:postgres
26 | volumes:
27 | - ../etc/services/matrix-synapse:/data
28 | - ./matrix-synapse-media-store:/media_store
29 |
30 | riot-web:
31 | image: bubuntux/riot-web:v1.3.3
32 | user: ${CURRENT_USER_UID}:${CURRENT_USER_GID}
33 | ports:
34 | - "41465:8080"
35 | volumes:
36 | - ../etc/services/matrix-riot-web/nginx.conf:/etc/nginx/nginx.conf:ro
37 | - /dev/null:/etc/nginx/conf.d/default.conf:ro
38 | - ../etc/services/matrix-riot-web/config.json:/etc/riot-web/config.json:ro
39 |
--------------------------------------------------------------------------------
/etc/services/matrix-riot-web/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "default_hs_url": "http://email2matrix.127.0.0.1.xip.io:41408",
3 | "default_is_url": "https://vector.im",
4 | "brand": "Riot",
5 | "integrations_ui_url": "https://scalar.vector.im/",
6 | "integrations_rest_url": "https://scalar.vector.im/api",
7 | "bug_report_endpoint_url": "https://riot.im/bugreports/submit",
8 | "enableLabs": true,
9 | "roomDirectory": {
10 | "servers": [
11 | "matrix.org"
12 | ]
13 | },
14 | "welcomeUserId": "@riot-bot:matrix.org"
15 | }
16 |
--------------------------------------------------------------------------------
/etc/services/matrix-riot-web/nginx.conf:
--------------------------------------------------------------------------------
1 | # This is a custom nginx configuration file that we use in the container (instead of the default one),
2 | # because it allows us to run nginx with a non-root user.
3 | #
4 | # For this to work, the default vhost file (`/etc/nginx/conf.d/default.conf`) also needs to be removed.
5 | # (mounting `/dev/null` over `/etc/nginx/conf.d/default.conf` works well)
6 | #
7 | # The following changes have been done compared to a default nginx configuration file:
8 | # - default server port is changed (80 -> 8080), so that a non-root user can bind it
9 | # - various temp paths are changed to `/tmp`, so that a non-root user can write to them
10 | # - the `user` directive was removed, as we don't want nginx to switch users
11 |
12 | worker_processes 1;
13 |
14 | error_log /var/log/nginx/error.log warn;
15 | pid /tmp/nginx.pid;
16 |
17 |
18 | events {
19 | worker_connections 1024;
20 | }
21 |
22 |
23 | http {
24 | client_body_temp_path /tmp/client_body_temp;
25 | proxy_temp_path /tmp/proxy_temp;
26 | fastcgi_temp_path /tmp/fastcgi_temp;
27 | uwsgi_temp_path /tmp/uwsgi_temp;
28 | scgi_temp_path /tmp/scgi_temp;
29 |
30 | include /etc/nginx/mime.types;
31 | default_type application/octet-stream;
32 |
33 | log_format main '$remote_addr - $remote_user [$time_local] "$request" '
34 | '$status $body_bytes_sent "$http_referer" '
35 | '"$http_user_agent" "$http_x_forwarded_for"';
36 |
37 | access_log /var/log/nginx/access.log main;
38 |
39 | sendfile on;
40 | #tcp_nopush on;
41 |
42 | keepalive_timeout 65;
43 |
44 | #gzip on;
45 |
46 | server {
47 | listen 8080;
48 | server_name localhost;
49 |
50 | location / {
51 | root /usr/share/nginx/html;
52 | index index.html index.htm;
53 | }
54 |
55 | error_page 500 502 503 504 /50x.html;
56 | location = /50x.html {
57 | root /usr/share/nginx/html;
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/etc/services/matrix-synapse/email2matrix.127.0.0.1.xip.io.log.config:
--------------------------------------------------------------------------------
1 | version: 1
2 |
3 | formatters:
4 | precise:
5 | format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s'
6 |
7 | filters:
8 | context:
9 | (): synapse.logging.context.LoggingContextFilter
10 | request: ""
11 |
12 | handlers:
13 | console:
14 | class: logging.StreamHandler
15 | formatter: precise
16 | filters: [context]
17 |
18 | loggers:
19 | synapse.storage.SQL:
20 | # beware: increasing this to DEBUG will make synapse log sensitive
21 | # information such as access tokens.
22 | level: INFO
23 |
24 | root:
25 | level: INFO
26 | handlers: [console]
--------------------------------------------------------------------------------
/etc/services/matrix-synapse/email2matrix.127.0.0.1.xip.io.signing.key:
--------------------------------------------------------------------------------
1 | ed25519 a_QLuA VClhyAChZfgG0Igdfi7cn2vpkZFnU7gh+/F22/F3nbg
2 |
--------------------------------------------------------------------------------
/etc/services/matrix-synapse/homeserver.yaml:
--------------------------------------------------------------------------------
1 | # vim:ft=yaml
2 |
3 | ## Server ##
4 |
5 | # The domain name of the server, with optional explicit port.
6 | # This is used by remote servers to connect to this server,
7 | # e.g. matrix.org, localhost:8080, etc.
8 | # This is also the last part of your UserID.
9 | #
10 | server_name: "email2matrix.127.0.0.1.xip.io"
11 |
12 | # When running as a daemon, the file to store the pid in
13 | #
14 | pid_file: /homeserver.pid
15 |
16 | # The path to the web client which will be served at /_matrix/client/
17 | # if 'webclient' is configured under the 'listeners' configuration.
18 | #
19 | #web_client_location: "/path/to/web/root"
20 |
21 | # The public-facing base URL that clients use to access this HS
22 | # (not including _matrix/...). This is the same URL a user would
23 | # enter into the 'custom HS URL' field on their client. If you
24 | # use synapse with a reverse proxy, this should be the URL to reach
25 | # synapse via the proxy.
26 | #
27 | #public_baseurl: https://example.com/
28 |
29 | # Set the soft limit on the number of file descriptors synapse can use
30 | # Zero is used to indicate synapse should set the soft limit to the
31 | # hard limit.
32 | #
33 | #soft_file_limit: 0
34 |
35 | # Set to false to disable presence tracking on this homeserver.
36 | #
37 | #use_presence: false
38 |
39 | # Whether to require authentication to retrieve profile data (avatars,
40 | # display names) of other users through the client API. Defaults to
41 | # 'false'. Note that profile data is also available via the federation
42 | # API, so this setting is of limited value if federation is enabled on
43 | # the server.
44 | #
45 | #require_auth_for_profile_requests: true
46 |
47 | # If set to 'false', requires authentication to access the server's public rooms
48 | # directory through the client API. Defaults to 'true'.
49 | #
50 | #allow_public_rooms_without_auth: false
51 |
52 | # If set to 'false', forbids any other homeserver to fetch the server's public
53 | # rooms directory via federation. Defaults to 'true'.
54 | #
55 | #allow_public_rooms_over_federation: false
56 |
57 | # The default room version for newly created rooms.
58 | #
59 | # Known room versions are listed here:
60 | # https://matrix.org/docs/spec/#complete-list-of-room-versions
61 | #
62 | # For example, for room version 1, default_room_version should be set
63 | # to "1".
64 | #
65 | #default_room_version: "4"
66 |
67 | # The GC threshold parameters to pass to `gc.set_threshold`, if defined
68 | #
69 | #gc_thresholds: [700, 10, 10]
70 |
71 | # Set the limit on the returned events in the timeline in the get
72 | # and sync operations. The default value is -1, means no upper limit.
73 | #
74 | #filter_timeline_limit: 5000
75 |
76 | # Whether room invites to users on this server should be blocked
77 | # (except those sent by local server admins). The default is False.
78 | #
79 | #block_non_admin_invites: True
80 |
81 | # Room searching
82 | #
83 | # If disabled, new messages will not be indexed for searching and users
84 | # will receive errors when searching for messages. Defaults to enabled.
85 | #
86 | #enable_search: false
87 |
88 | # Restrict federation to the following whitelist of domains.
89 | # N.B. we recommend also firewalling your federation listener to limit
90 | # inbound federation traffic as early as possible, rather than relying
91 | # purely on this application-layer restriction. If not specified, the
92 | # default is to whitelist everything.
93 | #
94 | #federation_domain_whitelist:
95 | # - lon.example.com
96 | # - nyc.example.com
97 | # - syd.example.com
98 |
99 | # Prevent federation requests from being sent to the following
100 | # blacklist IP address CIDR ranges. If this option is not specified, or
101 | # specified with an empty list, no ip range blacklist will be enforced.
102 | #
103 | # (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly
104 | # listed here, since they correspond to unroutable addresses.)
105 | #
106 | federation_ip_range_blacklist:
107 | - '127.0.0.0/8'
108 | - '10.0.0.0/8'
109 | - '172.16.0.0/12'
110 | - '192.168.0.0/16'
111 | - '100.64.0.0/10'
112 | - '169.254.0.0/16'
113 | - '::1/128'
114 | - 'fe80::/64'
115 | - 'fc00::/7'
116 |
117 | # List of ports that Synapse should listen on, their purpose and their
118 | # configuration.
119 | #
120 | # Options for each listener include:
121 | #
122 | # port: the TCP port to bind to
123 | #
124 | # bind_addresses: a list of local addresses to listen on. The default is
125 | # 'all local interfaces'.
126 | #
127 | # type: the type of listener. Normally 'http', but other valid options are:
128 | # 'manhole' (see docs/manhole.md),
129 | # 'metrics' (see docs/metrics-howto.rst),
130 | # 'replication' (see docs/workers.rst).
131 | #
132 | # tls: set to true to enable TLS for this listener. Will use the TLS
133 | # key/cert specified in tls_private_key_path / tls_certificate_path.
134 | #
135 | # x_forwarded: Only valid for an 'http' listener. Set to true to use the
136 | # X-Forwarded-For header as the client IP. Useful when Synapse is
137 | # behind a reverse-proxy.
138 | #
139 | # resources: Only valid for an 'http' listener. A list of resources to host
140 | # on this port. Options for each resource are:
141 | #
142 | # names: a list of names of HTTP resources. See below for a list of
143 | # valid resource names.
144 | #
145 | # compress: set to true to enable HTTP comression for this resource.
146 | #
147 | # additional_resources: Only valid for an 'http' listener. A map of
148 | # additional endpoints which should be loaded via dynamic modules.
149 | #
150 | # Valid resource names are:
151 | #
152 | # client: the client-server API (/_matrix/client), and the synapse admin
153 | # API (/_synapse/admin). Also implies 'media' and 'static'.
154 | #
155 | # consent: user consent forms (/_matrix/consent). See
156 | # docs/consent_tracking.md.
157 | #
158 | # federation: the server-server API (/_matrix/federation). Also implies
159 | # 'media', 'keys', 'openid'
160 | #
161 | # keys: the key discovery API (/_matrix/keys).
162 | #
163 | # media: the media API (/_matrix/media).
164 | #
165 | # metrics: the metrics interface. See docs/metrics-howto.rst.
166 | #
167 | # openid: OpenID authentication.
168 | #
169 | # replication: the HTTP replication API (/_synapse/replication). See
170 | # docs/workers.rst.
171 | #
172 | # static: static resources under synapse/static (/_matrix/static). (Mostly
173 | # useful for 'fallback authentication'.)
174 | #
175 | # webclient: A web client. Requires web_client_location to be set.
176 | #
177 | listeners:
178 | # TLS-enabled listener: for when matrix traffic is sent directly to synapse.
179 | #
180 | # Disabled by default. To enable it, uncomment the following. (Note that you
181 | # will also need to give Synapse a TLS key and certificate: see the TLS section
182 | # below.)
183 | #
184 | #- port: 8448
185 | # type: http
186 | # tls: true
187 | # resources:
188 | # - names: [client, federation]
189 |
190 | # Unsecure HTTP listener: for when matrix traffic passes through a reverse proxy
191 | # that unwraps TLS.
192 | #
193 | # If you plan to use a reverse proxy, please see
194 | # https://github.com/matrix-org/synapse/blob/master/docs/reverse_proxy.rst.
195 | #
196 | - port: 8008
197 | tls: false
198 | type: http
199 | x_forwarded: true
200 |
201 | resources:
202 | - names: [client, federation]
203 | compress: false
204 |
205 | # example additional_resources:
206 | #
207 | #additional_resources:
208 | # "/_matrix/my/custom/endpoint":
209 | # module: my_module.CustomRequestHandler
210 | # config: {}
211 |
212 | # Turn on the twisted ssh manhole service on localhost on the given
213 | # port.
214 | #
215 | #- port: 9000
216 | # bind_addresses: ['::1', '127.0.0.1']
217 | # type: manhole
218 |
219 |
220 | ## Homeserver blocking ##
221 |
222 | # How to reach the server admin, used in ResourceLimitError
223 | #
224 | #admin_contact: 'mailto:admin@server.com'
225 |
226 | # Global blocking
227 | #
228 | #hs_disabled: False
229 | #hs_disabled_message: 'Human readable reason for why the HS is blocked'
230 | #hs_disabled_limit_type: 'error code(str), to help clients decode reason'
231 |
232 | # Monthly Active User Blocking
233 | #
234 | # Used in cases where the admin or server owner wants to limit to the
235 | # number of monthly active users.
236 | #
237 | # 'limit_usage_by_mau' disables/enables monthly active user blocking. When
238 | # anabled and a limit is reached the server returns a 'ResourceLimitError'
239 | # with error type Codes.RESOURCE_LIMIT_EXCEEDED
240 | #
241 | # 'max_mau_value' is the hard limit of monthly active users above which
242 | # the server will start blocking user actions.
243 | #
244 | # 'mau_trial_days' is a means to add a grace period for active users. It
245 | # means that users must be active for this number of days before they
246 | # can be considered active and guards against the case where lots of users
247 | # sign up in a short space of time never to return after their initial
248 | # session.
249 | #
250 | #limit_usage_by_mau: False
251 | #max_mau_value: 50
252 | #mau_trial_days: 2
253 |
254 | # If enabled, the metrics for the number of monthly active users will
255 | # be populated, however no one will be limited. If limit_usage_by_mau
256 | # is true, this is implied to be true.
257 | #
258 | #mau_stats_only: False
259 |
260 | # Sometimes the server admin will want to ensure certain accounts are
261 | # never blocked by mau checking. These accounts are specified here.
262 | #
263 | #mau_limit_reserved_threepids:
264 | # - medium: 'email'
265 | # address: 'reserved_user@example.com'
266 |
267 | # Used by phonehome stats to group together related servers.
268 | #server_context: context
269 |
270 | # Whether to require a user to be in the room to add an alias to it.
271 | # Defaults to 'true'.
272 | #
273 | #require_membership_for_aliases: false
274 |
275 | # Whether to allow per-room membership profiles through the send of membership
276 | # events with profile information that differ from the target's global profile.
277 | # Defaults to 'true'.
278 | #
279 | #allow_per_room_profiles: false
280 |
281 |
282 | ## TLS ##
283 |
284 | # PEM-encoded X509 certificate for TLS.
285 | # This certificate, as of Synapse 1.0, will need to be a valid and verifiable
286 | # certificate, signed by a recognised Certificate Authority.
287 | #
288 | # See 'ACME support' below to enable auto-provisioning this certificate via
289 | # Let's Encrypt.
290 | #
291 | # If supplying your own, be sure to use a `.pem` file that includes the
292 | # full certificate chain including any intermediate certificates (for
293 | # instance, if using certbot, use `fullchain.pem` as your certificate,
294 | # not `cert.pem`).
295 | #
296 | #tls_certificate_path: "/data/email2matrix.127.0.0.1.xip.io.tls.crt"
297 |
298 | # PEM-encoded private key for TLS
299 | #
300 | #tls_private_key_path: "/data/email2matrix.127.0.0.1.xip.io.tls.key"
301 |
302 | # Whether to verify TLS server certificates for outbound federation requests.
303 | #
304 | # Defaults to `true`. To disable certificate verification, uncomment the
305 | # following line.
306 | #
307 | #federation_verify_certificates: false
308 |
309 | # The minimum TLS version that will be used for outbound federation requests.
310 | #
311 | # Defaults to `1`. Configurable to `1`, `1.1`, `1.2`, or `1.3`. Note
312 | # that setting this value higher than `1.2` will prevent federation to most
313 | # of the public Matrix network: only configure it to `1.3` if you have an
314 | # entirely private federation setup and you can ensure TLS 1.3 support.
315 | #
316 | #federation_client_minimum_tls_version: 1.2
317 |
318 | # Skip federation certificate verification on the following whitelist
319 | # of domains.
320 | #
321 | # This setting should only be used in very specific cases, such as
322 | # federation over Tor hidden services and similar. For private networks
323 | # of homeservers, you likely want to use a private CA instead.
324 | #
325 | # Only effective if federation_verify_certicates is `true`.
326 | #
327 | #federation_certificate_verification_whitelist:
328 | # - lon.example.com
329 | # - *.domain.com
330 | # - *.onion
331 |
332 | # List of custom certificate authorities for federation traffic.
333 | #
334 | # This setting should only normally be used within a private network of
335 | # homeservers.
336 | #
337 | # Note that this list will replace those that are provided by your
338 | # operating environment. Certificates must be in PEM format.
339 | #
340 | #federation_custom_ca_list:
341 | # - myCA1.pem
342 | # - myCA2.pem
343 | # - myCA3.pem
344 |
345 | # ACME support: This will configure Synapse to request a valid TLS certificate
346 | # for your configured `server_name` via Let's Encrypt.
347 | #
348 | # Note that provisioning a certificate in this way requires port 80 to be
349 | # routed to Synapse so that it can complete the http-01 ACME challenge.
350 | # By default, if you enable ACME support, Synapse will attempt to listen on
351 | # port 80 for incoming http-01 challenges - however, this will likely fail
352 | # with 'Permission denied' or a similar error.
353 | #
354 | # There are a couple of potential solutions to this:
355 | #
356 | # * If you already have an Apache, Nginx, or similar listening on port 80,
357 | # you can configure Synapse to use an alternate port, and have your web
358 | # server forward the requests. For example, assuming you set 'port: 8009'
359 | # below, on Apache, you would write:
360 | #
361 | # ProxyPass /.well-known/acme-challenge http://localhost:8009/.well-known/acme-challenge
362 | #
363 | # * Alternatively, you can use something like `authbind` to give Synapse
364 | # permission to listen on port 80.
365 | #
366 | acme:
367 | # ACME support is disabled by default. Uncomment the following line
368 | # (and tls_certificate_path and tls_private_key_path above) to enable it.
369 | #
370 | #enabled: true
371 |
372 | # Endpoint to use to request certificates. If you only want to test,
373 | # use Let's Encrypt's staging url:
374 | # https://acme-staging.api.letsencrypt.org/directory
375 | #
376 | #url: https://acme-v01.api.letsencrypt.org/directory
377 |
378 | # Port number to listen on for the HTTP-01 challenge. Change this if
379 | # you are forwarding connections through Apache/Nginx/etc.
380 | #
381 | #port: 80
382 |
383 | # Local addresses to listen on for incoming connections.
384 | # Again, you may want to change this if you are forwarding connections
385 | # through Apache/Nginx/etc.
386 | #
387 | #bind_addresses: ['::', '0.0.0.0']
388 |
389 | # How many days remaining on a certificate before it is renewed.
390 | #
391 | #reprovision_threshold: 30
392 |
393 | # The domain that the certificate should be for. Normally this
394 | # should be the same as your Matrix domain (i.e., 'server_name'), but,
395 | # by putting a file at 'https:///.well-known/matrix/server',
396 | # you can delegate incoming traffic to another server. If you do that,
397 | # you should give the target of the delegation here.
398 | #
399 | # For example: if your 'server_name' is 'example.com', but
400 | # 'https://example.com/.well-known/matrix/server' delegates to
401 | # 'matrix.example.com', you should put 'matrix.example.com' here.
402 | #
403 | # If not set, defaults to your 'server_name'.
404 | #
405 | #domain: matrix.example.com
406 |
407 | # file to use for the account key. This will be generated if it doesn't
408 | # exist.
409 | #
410 | # If unspecified, we will use CONFDIR/client.key.
411 | #
412 | account_key_file: /data/acme_account.key
413 |
414 | # List of allowed TLS fingerprints for this server to publish along
415 | # with the signing keys for this server. Other matrix servers that
416 | # make HTTPS requests to this server will check that the TLS
417 | # certificates returned by this server match one of the fingerprints.
418 | #
419 | # Synapse automatically adds the fingerprint of its own certificate
420 | # to the list. So if federation traffic is handled directly by synapse
421 | # then no modification to the list is required.
422 | #
423 | # If synapse is run behind a load balancer that handles the TLS then it
424 | # will be necessary to add the fingerprints of the certificates used by
425 | # the loadbalancers to this list if they are different to the one
426 | # synapse is using.
427 | #
428 | # Homeservers are permitted to cache the list of TLS fingerprints
429 | # returned in the key responses up to the "valid_until_ts" returned in
430 | # key. It may be necessary to publish the fingerprints of a new
431 | # certificate and wait until the "valid_until_ts" of the previous key
432 | # responses have passed before deploying it.
433 | #
434 | # You can calculate a fingerprint from a given TLS listener via:
435 | # openssl s_client -connect $host:$port < /dev/null 2> /dev/null |
436 | # openssl x509 -outform DER | openssl sha256 -binary | base64 | tr -d '='
437 | # or by checking matrix.org/federationtester/api/report?server_name=$host
438 | #
439 | #tls_fingerprints: [{"sha256": ""}]
440 |
441 |
442 |
443 | ## Database ##
444 |
445 | database:
446 | # The database engine name
447 | name: "psycopg2"
448 | args:
449 | user: "synapse"
450 | password: "synapse-password"
451 | database: "homeserver"
452 | host: "postgres"
453 | cp_min: 5
454 | cp_max: 10
455 |
456 | # Number of events to cache in memory.
457 | #
458 | #event_cache_size: 10K
459 |
460 |
461 | ## Logging ##
462 |
463 | # A yaml python logging config file
464 | #
465 | log_config: "/data/email2matrix.127.0.0.1.xip.io.log.config"
466 |
467 |
468 | ## Ratelimiting ##
469 |
470 | # Ratelimiting settings for client actions (registration, login, messaging).
471 | #
472 | # Each ratelimiting configuration is made of two parameters:
473 | # - per_second: number of requests a client can send per second.
474 | # - burst_count: number of requests a client can send before being throttled.
475 | #
476 | # Synapse currently uses the following configurations:
477 | # - one for messages that ratelimits sending based on the account the client
478 | # is using
479 | # - one for registration that ratelimits registration requests based on the
480 | # client's IP address.
481 | # - one for login that ratelimits login requests based on the client's IP
482 | # address.
483 | # - one for login that ratelimits login requests based on the account the
484 | # client is attempting to log into.
485 | # - one for login that ratelimits login requests based on the account the
486 | # client is attempting to log into, based on the amount of failed login
487 | # attempts for this account.
488 | #
489 | # The defaults are as shown below.
490 | #
491 | #rc_message:
492 | # per_second: 0.2
493 | # burst_count: 10
494 | #
495 | #rc_registration:
496 | # per_second: 0.17
497 | # burst_count: 3
498 | #
499 | #rc_login:
500 | # address:
501 | # per_second: 0.17
502 | # burst_count: 3
503 | # account:
504 | # per_second: 0.17
505 | # burst_count: 3
506 | # failed_attempts:
507 | # per_second: 0.17
508 | # burst_count: 3
509 |
510 |
511 | # Ratelimiting settings for incoming federation
512 | #
513 | # The rc_federation configuration is made up of the following settings:
514 | # - window_size: window size in milliseconds
515 | # - sleep_limit: number of federation requests from a single server in
516 | # a window before the server will delay processing the request.
517 | # - sleep_delay: duration in milliseconds to delay processing events
518 | # from remote servers by if they go over the sleep limit.
519 | # - reject_limit: maximum number of concurrent federation requests
520 | # allowed from a single server
521 | # - concurrent: number of federation requests to concurrently process
522 | # from a single server
523 | #
524 | # The defaults are as shown below.
525 | #
526 | #rc_federation:
527 | # window_size: 1000
528 | # sleep_limit: 10
529 | # sleep_delay: 500
530 | # reject_limit: 50
531 | # concurrent: 3
532 |
533 | # Target outgoing federation transaction frequency for sending read-receipts,
534 | # per-room.
535 | #
536 | # If we end up trying to send out more read-receipts, they will get buffered up
537 | # into fewer transactions.
538 | #
539 | #federation_rr_transactions_per_room_per_second: 50
540 |
541 |
542 |
543 | # Directory where uploaded images and attachments are stored.
544 | #
545 | media_store_path: "/media_store"
546 |
547 | # Media storage providers allow media to be stored in different
548 | # locations.
549 | #
550 | #media_storage_providers:
551 | # - module: file_system
552 | # # Whether to write new local files.
553 | # store_local: false
554 | # # Whether to write new remote media
555 | # store_remote: false
556 | # # Whether to block upload requests waiting for write to this
557 | # # provider to complete
558 | # store_synchronous: false
559 | # config:
560 | # directory: /mnt/some/other/directory
561 |
562 | # Directory where in-progress uploads are stored.
563 | #
564 | uploads_path: "/tmp"
565 |
566 | # The largest allowed upload size in bytes
567 | #
568 | #max_upload_size: 10M
569 |
570 | # Maximum number of pixels that will be thumbnailed
571 | #
572 | #max_image_pixels: 32M
573 |
574 | # Whether to generate new thumbnails on the fly to precisely match
575 | # the resolution requested by the client. If true then whenever
576 | # a new resolution is requested by the client the server will
577 | # generate a new thumbnail. If false the server will pick a thumbnail
578 | # from a precalculated list.
579 | #
580 | #dynamic_thumbnails: false
581 |
582 | # List of thumbnails to precalculate when an image is uploaded.
583 | #
584 | #thumbnail_sizes:
585 | # - width: 32
586 | # height: 32
587 | # method: crop
588 | # - width: 96
589 | # height: 96
590 | # method: crop
591 | # - width: 320
592 | # height: 240
593 | # method: scale
594 | # - width: 640
595 | # height: 480
596 | # method: scale
597 | # - width: 800
598 | # height: 600
599 | # method: scale
600 |
601 | # Is the preview URL API enabled?
602 | #
603 | # 'false' by default: uncomment the following to enable it (and specify a
604 | # url_preview_ip_range_blacklist blacklist).
605 | #
606 | #url_preview_enabled: true
607 |
608 | # List of IP address CIDR ranges that the URL preview spider is denied
609 | # from accessing. There are no defaults: you must explicitly
610 | # specify a list for URL previewing to work. You should specify any
611 | # internal services in your network that you do not want synapse to try
612 | # to connect to, otherwise anyone in any Matrix room could cause your
613 | # synapse to issue arbitrary GET requests to your internal services,
614 | # causing serious security issues.
615 | #
616 | # (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly
617 | # listed here, since they correspond to unroutable addresses.)
618 | #
619 | # This must be specified if url_preview_enabled is set. It is recommended that
620 | # you uncomment the following list as a starting point.
621 | #
622 | #url_preview_ip_range_blacklist:
623 | # - '127.0.0.0/8'
624 | # - '10.0.0.0/8'
625 | # - '172.16.0.0/12'
626 | # - '192.168.0.0/16'
627 | # - '100.64.0.0/10'
628 | # - '169.254.0.0/16'
629 | # - '::1/128'
630 | # - 'fe80::/64'
631 | # - 'fc00::/7'
632 |
633 | # List of IP address CIDR ranges that the URL preview spider is allowed
634 | # to access even if they are specified in url_preview_ip_range_blacklist.
635 | # This is useful for specifying exceptions to wide-ranging blacklisted
636 | # target IP ranges - e.g. for enabling URL previews for a specific private
637 | # website only visible in your network.
638 | #
639 | #url_preview_ip_range_whitelist:
640 | # - '192.168.1.1'
641 |
642 | # Optional list of URL matches that the URL preview spider is
643 | # denied from accessing. You should use url_preview_ip_range_blacklist
644 | # in preference to this, otherwise someone could define a public DNS
645 | # entry that points to a private IP address and circumvent the blacklist.
646 | # This is more useful if you know there is an entire shape of URL that
647 | # you know that will never want synapse to try to spider.
648 | #
649 | # Each list entry is a dictionary of url component attributes as returned
650 | # by urlparse.urlsplit as applied to the absolute form of the URL. See
651 | # https://docs.python.org/2/library/urlparse.html#urlparse.urlsplit
652 | # The values of the dictionary are treated as an filename match pattern
653 | # applied to that component of URLs, unless they start with a ^ in which
654 | # case they are treated as a regular expression match. If all the
655 | # specified component matches for a given list item succeed, the URL is
656 | # blacklisted.
657 | #
658 | #url_preview_url_blacklist:
659 | # # blacklist any URL with a username in its URI
660 | # - username: '*'
661 | #
662 | # # blacklist all *.google.com URLs
663 | # - netloc: 'google.com'
664 | # - netloc: '*.google.com'
665 | #
666 | # # blacklist all plain HTTP URLs
667 | # - scheme: 'http'
668 | #
669 | # # blacklist http(s)://www.acme.com/foo
670 | # - netloc: 'www.acme.com'
671 | # path: '/foo'
672 | #
673 | # # blacklist any URL with a literal IPv4 address
674 | # - netloc: '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'
675 |
676 | # The largest allowed URL preview spidering size in bytes
677 | #
678 | #max_spider_size: 10M
679 |
680 |
681 | ## Captcha ##
682 | # See docs/CAPTCHA_SETUP for full details of configuring this.
683 |
684 | # This Home Server's ReCAPTCHA public key.
685 | #
686 | #recaptcha_public_key: "YOUR_PUBLIC_KEY"
687 |
688 | # This Home Server's ReCAPTCHA private key.
689 | #
690 | #recaptcha_private_key: "YOUR_PRIVATE_KEY"
691 |
692 | # Enables ReCaptcha checks when registering, preventing signup
693 | # unless a captcha is answered. Requires a valid ReCaptcha
694 | # public/private key.
695 | #
696 | #enable_registration_captcha: false
697 |
698 | # A secret key used to bypass the captcha test entirely.
699 | #
700 | #captcha_bypass_secret: "YOUR_SECRET_HERE"
701 |
702 | # The API endpoint to use for verifying m.login.recaptcha responses.
703 | #
704 | #recaptcha_siteverify_api: "https://www.recaptcha.net/recaptcha/api/siteverify"
705 |
706 |
707 | ## TURN ##
708 |
709 | # The public URIs of the TURN server to give to clients
710 | #
711 | #turn_uris: []
712 |
713 | # The shared secret used to compute passwords for the TURN server
714 | #
715 | #turn_shared_secret: "YOUR_SHARED_SECRET"
716 |
717 | # The Username and password if the TURN server needs them and
718 | # does not use a token
719 | #
720 | #turn_username: "TURNSERVER_USERNAME"
721 | #turn_password: "TURNSERVER_PASSWORD"
722 |
723 | # How long generated TURN credentials last
724 | #
725 | #turn_user_lifetime: 1h
726 |
727 | # Whether guests should be allowed to use the TURN server.
728 | # This defaults to True, otherwise VoIP will be unreliable for guests.
729 | # However, it does introduce a slight security risk as it allows users to
730 | # connect to arbitrary endpoints without having first signed up for a
731 | # valid account (e.g. by passing a CAPTCHA).
732 | #
733 | #turn_allow_guests: True
734 |
735 |
736 | ## Registration ##
737 | #
738 | # Registration can be rate-limited using the parameters in the "Ratelimiting"
739 | # section of this file.
740 |
741 | # Enable registration for new users.
742 | #
743 | #enable_registration: false
744 |
745 | # Optional account validity configuration. This allows for accounts to be denied
746 | # any request after a given period.
747 | #
748 | # ``enabled`` defines whether the account validity feature is enabled. Defaults
749 | # to False.
750 | #
751 | # ``period`` allows setting the period after which an account is valid
752 | # after its registration. When renewing the account, its validity period
753 | # will be extended by this amount of time. This parameter is required when using
754 | # the account validity feature.
755 | #
756 | # ``renew_at`` is the amount of time before an account's expiry date at which
757 | # Synapse will send an email to the account's email address with a renewal link.
758 | # This needs the ``email`` and ``public_baseurl`` configuration sections to be
759 | # filled.
760 | #
761 | # ``renew_email_subject`` is the subject of the email sent out with the renewal
762 | # link. ``%(app)s`` can be used as a placeholder for the ``app_name`` parameter
763 | # from the ``email`` section.
764 | #
765 | # Once this feature is enabled, Synapse will look for registered users without an
766 | # expiration date at startup and will add one to every account it found using the
767 | # current settings at that time.
768 | # This means that, if a validity period is set, and Synapse is restarted (it will
769 | # then derive an expiration date from the current validity period), and some time
770 | # after that the validity period changes and Synapse is restarted, the users'
771 | # expiration dates won't be updated unless their account is manually renewed. This
772 | # date will be randomly selected within a range [now + period - d ; now + period],
773 | # where d is equal to 10% of the validity period.
774 | #
775 | #account_validity:
776 | # enabled: True
777 | # period: 6w
778 | # renew_at: 1w
779 | # renew_email_subject: "Renew your %(app)s account"
780 |
781 | # Time that a user's session remains valid for, after they log in.
782 | #
783 | # Note that this is not currently compatible with guest logins.
784 | #
785 | # Note also that this is calculated at login time: changes are not applied
786 | # retrospectively to users who have already logged in.
787 | #
788 | # By default, this is infinite.
789 | #
790 | #session_lifetime: 24h
791 |
792 | # The user must provide all of the below types of 3PID when registering.
793 | #
794 | #registrations_require_3pid:
795 | # - email
796 | # - msisdn
797 |
798 | # Explicitly disable asking for MSISDNs from the registration
799 | # flow (overrides registrations_require_3pid if MSISDNs are set as required)
800 | #
801 | #disable_msisdn_registration: true
802 |
803 | # Mandate that users are only allowed to associate certain formats of
804 | # 3PIDs with accounts on this server.
805 | #
806 | #allowed_local_3pids:
807 | # - medium: email
808 | # pattern: '.*@matrix\.org'
809 | # - medium: email
810 | # pattern: '.*@vector\.im'
811 | # - medium: msisdn
812 | # pattern: '\+44'
813 |
814 | # Enable 3PIDs lookup requests to identity servers from this server.
815 | #
816 | #enable_3pid_lookup: true
817 |
818 | # If set, allows registration of standard or admin accounts by anyone who
819 | # has the shared secret, even if registration is otherwise disabled.
820 | #
821 | registration_shared_secret: "St@nZP7wE5v;U&9s#fCY3BAkk._DMgRZM7dMVl&FYlcTZGnz.3"
822 |
823 | # Set the number of bcrypt rounds used to generate password hash.
824 | # Larger numbers increase the work factor needed to generate the hash.
825 | # The default number is 12 (which equates to 2^12 rounds).
826 | # N.B. that increasing this will exponentially increase the time required
827 | # to register or login - e.g. 24 => 2^24 rounds which will take >20 mins.
828 | #
829 | #bcrypt_rounds: 12
830 |
831 | # Allows users to register as guests without a password/email/etc, and
832 | # participate in rooms hosted on this server which have been made
833 | # accessible to anonymous users.
834 | #
835 | #allow_guest_access: false
836 |
837 | # The identity server which we suggest that clients should use when users log
838 | # in on this server.
839 | #
840 | # (By default, no suggestion is made, so it is left up to the client.
841 | # This setting is ignored unless public_baseurl is also set.)
842 | #
843 | #default_identity_server: https://matrix.org
844 |
845 | # The list of identity servers trusted to verify third party
846 | # identifiers by this server.
847 | #
848 | # Also defines the ID server which will be called when an account is
849 | # deactivated (one will be picked arbitrarily).
850 | #
851 | #trusted_third_party_id_servers:
852 | # - matrix.org
853 | # - vector.im
854 |
855 | # Users who register on this homeserver will automatically be joined
856 | # to these rooms
857 | #
858 | #auto_join_rooms:
859 | # - "#example:example.com"
860 |
861 | # Where auto_join_rooms are specified, setting this flag ensures that the
862 | # the rooms exist by creating them when the first user on the
863 | # homeserver registers.
864 | # Setting to false means that if the rooms are not manually created,
865 | # users cannot be auto-joined since they do not exist.
866 | #
867 | #autocreate_auto_join_rooms: true
868 |
869 |
870 | ## Metrics ###
871 |
872 | # Enable collection and rendering of performance metrics
873 | #
874 | #enable_metrics: False
875 |
876 | # Enable sentry integration
877 | # NOTE: While attempts are made to ensure that the logs don't contain
878 | # any sensitive information, this cannot be guaranteed. By enabling
879 | # this option the sentry server may therefore receive sensitive
880 | # information, and it in turn may then diseminate sensitive information
881 | # through insecure notification channels if so configured.
882 | #
883 | #sentry:
884 | # dsn: "..."
885 |
886 | # Whether or not to report anonymized homeserver usage statistics.
887 | report_stats: false
888 |
889 |
890 | ## API Configuration ##
891 |
892 | # A list of event types that will be included in the room_invite_state
893 | #
894 | #room_invite_state_types:
895 | # - "m.room.join_rules"
896 | # - "m.room.canonical_alias"
897 | # - "m.room.avatar"
898 | # - "m.room.encryption"
899 | # - "m.room.name"
900 |
901 |
902 | # A list of application service config files to use
903 | #
904 | #app_service_config_files:
905 | # - app_service_1.yaml
906 | # - app_service_2.yaml
907 |
908 | # Uncomment to enable tracking of application service IP addresses. Implicitly
909 | # enables MAU tracking for application service users.
910 | #
911 | #track_appservice_user_ips: True
912 |
913 |
914 | # a secret which is used to sign access tokens. If none is specified,
915 | # the registration_shared_secret is used, if one is given; otherwise,
916 | # a secret key is derived from the signing key.
917 | #
918 | macaroon_secret_key: "pr9zwi876nQt*#9+PADX.0KOb6=JGg#,@o&~,sHj5VLpLoR+,:"
919 |
920 | # Used to enable access token expiration.
921 | #
922 | #expire_access_token: False
923 |
924 | # a secret which is used to calculate HMACs for form values, to stop
925 | # falsification of values. Must be specified for the User Consent
926 | # forms to work.
927 | #
928 | form_secret: "94eqA^p81n_@ZTWZUov^RyXSjA~zQv:y9#PB*pdQZU6@OwHPnS"
929 |
930 | ## Signing Keys ##
931 |
932 | # Path to the signing key to sign messages with
933 | #
934 | signing_key_path: "/data/email2matrix.127.0.0.1.xip.io.signing.key"
935 |
936 | # The keys that the server used to sign messages with but won't use
937 | # to sign new messages. E.g. it has lost its private key
938 | #
939 | #old_signing_keys:
940 | # "ed25519:auto":
941 | # # Base64 encoded public key
942 | # key: "The public part of your old signing key."
943 | # # Millisecond POSIX timestamp when the key expired.
944 | # expired_ts: 123456789123
945 |
946 | # How long key response published by this server is valid for.
947 | # Used to set the valid_until_ts in /key/v2 APIs.
948 | # Determines how quickly servers will query to check which keys
949 | # are still valid.
950 | #
951 | #key_refresh_interval: 1d
952 |
953 | # The trusted servers to download signing keys from.
954 | #
955 | # When we need to fetch a signing key, each server is tried in parallel.
956 | #
957 | # Normally, the connection to the key server is validated via TLS certificates.
958 | # Additional security can be provided by configuring a `verify key`, which
959 | # will make synapse check that the response is signed by that key.
960 | #
961 | # This setting supercedes an older setting named `perspectives`. The old format
962 | # is still supported for backwards-compatibility, but it is deprecated.
963 | #
964 | # Options for each entry in the list include:
965 | #
966 | # server_name: the name of the server. required.
967 | #
968 | # verify_keys: an optional map from key id to base64-encoded public key.
969 | # If specified, we will check that the response is signed by at least
970 | # one of the given keys.
971 | #
972 | # accept_keys_insecurely: a boolean. Normally, if `verify_keys` is unset,
973 | # and federation_verify_certificates is not `true`, synapse will refuse
974 | # to start, because this would allow anyone who can spoof DNS responses
975 | # to masquerade as the trusted key server. If you know what you are doing
976 | # and are sure that your network environment provides a secure connection
977 | # to the key server, you can set this to `true` to override this
978 | # behaviour.
979 | #
980 | # An example configuration might look like:
981 | #
982 | #trusted_key_servers:
983 | # - server_name: "my_trusted_server.example.com"
984 | # verify_keys:
985 | # "ed25519:auto": "abcdefghijklmnopqrstuvwxyzabcdefghijklmopqr"
986 | # - server_name: "my_other_trusted_server.example.com"
987 | #
988 | # The default configuration is:
989 | #
990 | #trusted_key_servers:
991 | # - server_name: "matrix.org"
992 |
993 |
994 | # Enable SAML2 for registration and login. Uses pysaml2.
995 | #
996 | # `sp_config` is the configuration for the pysaml2 Service Provider.
997 | # See pysaml2 docs for format of config.
998 | #
999 | # Default values will be used for the 'entityid' and 'service' settings,
1000 | # so it is not normally necessary to specify them unless you need to
1001 | # override them.
1002 | #
1003 | # Once SAML support is enabled, a metadata file will be exposed at
1004 | # https://:/_matrix/saml2/metadata.xml, which you may be able to
1005 | # use to configure your SAML IdP with. Alternatively, you can manually configure
1006 | # the IdP to use an ACS location of
1007 | # https://:/_matrix/saml2/authn_response.
1008 | #
1009 | #saml2_config:
1010 | # sp_config:
1011 | # # point this to the IdP's metadata. You can use either a local file or
1012 | # # (preferably) a URL.
1013 | # metadata:
1014 | # #local: ["saml2/idp.xml"]
1015 | # remote:
1016 | # - url: https://our_idp/metadata.xml
1017 | #
1018 | # # By default, the user has to go to our login page first. If you'd like to
1019 | # # allow IdP-initiated login, set 'allow_unsolicited: True' in a
1020 | # # 'service.sp' section:
1021 | # #
1022 | # #service:
1023 | # # sp:
1024 | # # allow_unsolicited: True
1025 | #
1026 | # # The examples below are just used to generate our metadata xml, and you
1027 | # # may well not need it, depending on your setup. Alternatively you
1028 | # # may need a whole lot more detail - see the pysaml2 docs!
1029 | #
1030 | # description: ["My awesome SP", "en"]
1031 | # name: ["Test SP", "en"]
1032 | #
1033 | # organization:
1034 | # name: Example com
1035 | # display_name:
1036 | # - ["Example co", "en"]
1037 | # url: "http://example.com"
1038 | #
1039 | # contact_person:
1040 | # - given_name: Bob
1041 | # sur_name: "the Sysadmin"
1042 | # email_address": ["admin@example.com"]
1043 | # contact_type": technical
1044 | #
1045 | # # Instead of putting the config inline as above, you can specify a
1046 | # # separate pysaml2 configuration file:
1047 | # #
1048 | # config_path: "/data/sp_conf.py"
1049 | #
1050 | # # the lifetime of a SAML session. This defines how long a user has to
1051 | # # complete the authentication process, if allow_unsolicited is unset.
1052 | # # The default is 5 minutes.
1053 | # #
1054 | # # saml_session_lifetime: 5m
1055 |
1056 |
1057 |
1058 | # Enable CAS for registration and login.
1059 | #
1060 | #cas_config:
1061 | # enabled: true
1062 | # server_url: "https://cas-server.com"
1063 | # service_url: "https://homeserver.domain.com:8448"
1064 | # #required_attributes:
1065 | # # name: value
1066 |
1067 |
1068 | # The JWT needs to contain a globally unique "sub" (subject) claim.
1069 | #
1070 | #jwt_config:
1071 | # enabled: true
1072 | # secret: "a secret"
1073 | # algorithm: "HS256"
1074 |
1075 |
1076 | password_config:
1077 | # Uncomment to disable password login
1078 | #
1079 | #enabled: false
1080 |
1081 | # Uncomment to disable authentication against the local password
1082 | # database. This is ignored if `enabled` is false, and is only useful
1083 | # if you have other password_providers.
1084 | #
1085 | #localdb_enabled: false
1086 |
1087 | # Uncomment and change to a secret random string for extra security.
1088 | # DO NOT CHANGE THIS AFTER INITIAL SETUP!
1089 | #
1090 | #pepper: "EVEN_MORE_SECRET"
1091 |
1092 |
1093 |
1094 | # Enable sending emails for password resets, notification events or
1095 | # account expiry notices
1096 | #
1097 | # If your SMTP server requires authentication, the optional smtp_user &
1098 | # smtp_pass variables should be used
1099 | #
1100 | #email:
1101 | # enable_notifs: false
1102 | # smtp_host: "localhost"
1103 | # smtp_port: 25 # SSL: 465, STARTTLS: 587
1104 | # smtp_user: "exampleusername"
1105 | # smtp_pass: "examplepassword"
1106 | # require_transport_security: False
1107 | # notif_from: "Your Friendly %(app)s Home Server "
1108 | # app_name: Matrix
1109 | #
1110 | # # Enable email notifications by default
1111 | # #
1112 | # notif_for_new_users: True
1113 | #
1114 | # # Defining a custom URL for Riot is only needed if email notifications
1115 | # # should contain links to a self-hosted installation of Riot; when set
1116 | # # the "app_name" setting is ignored
1117 | # #
1118 | # riot_base_url: "http://localhost/riot"
1119 | #
1120 | # # Enable sending password reset emails via the configured, trusted
1121 | # # identity servers
1122 | # #
1123 | # # IMPORTANT! This will give a malicious or overtaken identity server
1124 | # # the ability to reset passwords for your users! Make absolutely sure
1125 | # # that you want to do this! It is strongly recommended that password
1126 | # # reset emails be sent by the homeserver instead
1127 | # #
1128 | # # If this option is set to false and SMTP options have not been
1129 | # # configured, resetting user passwords via email will be disabled
1130 | # #
1131 | # #trust_identity_server_for_password_resets: false
1132 | #
1133 | # # Configure the time that a validation email or text message code
1134 | # # will expire after sending
1135 | # #
1136 | # # This is currently used for password resets
1137 | # #
1138 | # #validation_token_lifetime: 1h
1139 | #
1140 | # # Template directory. All template files should be stored within this
1141 | # # directory. If not set, default templates from within the Synapse
1142 | # # package will be used
1143 | # #
1144 | # # For the list of default templates, please see
1145 | # # https://github.com/matrix-org/synapse/tree/master/synapse/res/templates
1146 | # #
1147 | # #template_dir: res/templates
1148 | #
1149 | # # Templates for email notifications
1150 | # #
1151 | # notif_template_html: notif_mail.html
1152 | # notif_template_text: notif_mail.txt
1153 | #
1154 | # # Templates for account expiry notices
1155 | # #
1156 | # expiry_template_html: notice_expiry.html
1157 | # expiry_template_text: notice_expiry.txt
1158 | #
1159 | # # Templates for password reset emails sent by the homeserver
1160 | # #
1161 | # #password_reset_template_html: password_reset.html
1162 | # #password_reset_template_text: password_reset.txt
1163 | #
1164 | # # Templates for password reset success and failure pages that a user
1165 | # # will see after attempting to reset their password
1166 | # #
1167 | # #password_reset_template_success_html: password_reset_success.html
1168 | # #password_reset_template_failure_html: password_reset_failure.html
1169 |
1170 |
1171 | #password_providers:
1172 | # - module: "ldap_auth_provider.LdapAuthProvider"
1173 | # config:
1174 | # enabled: true
1175 | # uri: "ldap://ldap.example.com:389"
1176 | # start_tls: true
1177 | # base: "ou=users,dc=example,dc=com"
1178 | # attributes:
1179 | # uid: "cn"
1180 | # mail: "email"
1181 | # name: "givenName"
1182 | # #bind_dn:
1183 | # #bind_password:
1184 | # #filter: "(objectClass=posixAccount)"
1185 |
1186 |
1187 |
1188 | # Clients requesting push notifications can either have the body of
1189 | # the message sent in the notification poke along with other details
1190 | # like the sender, or just the event ID and room ID (`event_id_only`).
1191 | # If clients choose the former, this option controls whether the
1192 | # notification request includes the content of the event (other details
1193 | # like the sender are still included). For `event_id_only` push, it
1194 | # has no effect.
1195 | #
1196 | # For modern android devices the notification content will still appear
1197 | # because it is loaded by the app. iPhone, however will send a
1198 | # notification saying only that a message arrived and who it came from.
1199 | #
1200 | #push:
1201 | # include_content: true
1202 |
1203 |
1204 | #spam_checker:
1205 | # module: "my_custom_project.SuperSpamChecker"
1206 | # config:
1207 | # example_option: 'things'
1208 |
1209 |
1210 | # Uncomment to allow non-server-admin users to create groups on this server
1211 | #
1212 | #enable_group_creation: true
1213 |
1214 | # If enabled, non server admins can only create groups with local parts
1215 | # starting with this prefix
1216 | #
1217 | #group_creation_prefix: "unofficial/"
1218 |
1219 |
1220 |
1221 | # User Directory configuration
1222 | #
1223 | # 'enabled' defines whether users can search the user directory. If
1224 | # false then empty responses are returned to all queries. Defaults to
1225 | # true.
1226 | #
1227 | # 'search_all_users' defines whether to search all users visible to your HS
1228 | # when searching the user directory, rather than limiting to users visible
1229 | # in public rooms. Defaults to false. If you set it True, you'll have to
1230 | # rebuild the user_directory search indexes, see
1231 | # https://github.com/matrix-org/synapse/blob/master/docs/user_directory.md
1232 | #
1233 | #user_directory:
1234 | # enabled: true
1235 | # search_all_users: false
1236 |
1237 |
1238 | # User Consent configuration
1239 | #
1240 | # for detailed instructions, see
1241 | # https://github.com/matrix-org/synapse/blob/master/docs/consent_tracking.md
1242 | #
1243 | # Parts of this section are required if enabling the 'consent' resource under
1244 | # 'listeners', in particular 'template_dir' and 'version'.
1245 | #
1246 | # 'template_dir' gives the location of the templates for the HTML forms.
1247 | # This directory should contain one subdirectory per language (eg, 'en', 'fr'),
1248 | # and each language directory should contain the policy document (named as
1249 | # '.html') and a success page (success.html).
1250 | #
1251 | # 'version' specifies the 'current' version of the policy document. It defines
1252 | # the version to be served by the consent resource if there is no 'v'
1253 | # parameter.
1254 | #
1255 | # 'server_notice_content', if enabled, will send a user a "Server Notice"
1256 | # asking them to consent to the privacy policy. The 'server_notices' section
1257 | # must also be configured for this to work. Notices will *not* be sent to
1258 | # guest users unless 'send_server_notice_to_guests' is set to true.
1259 | #
1260 | # 'block_events_error', if set, will block any attempts to send events
1261 | # until the user consents to the privacy policy. The value of the setting is
1262 | # used as the text of the error.
1263 | #
1264 | # 'require_at_registration', if enabled, will add a step to the registration
1265 | # process, similar to how captcha works. Users will be required to accept the
1266 | # policy before their account is created.
1267 | #
1268 | # 'policy_name' is the display name of the policy users will see when registering
1269 | # for an account. Has no effect unless `require_at_registration` is enabled.
1270 | # Defaults to "Privacy Policy".
1271 | #
1272 | #user_consent:
1273 | # template_dir: res/templates/privacy
1274 | # version: 1.0
1275 | # server_notice_content:
1276 | # msgtype: m.text
1277 | # body: >-
1278 | # To continue using this homeserver you must review and agree to the
1279 | # terms and conditions at %(consent_uri)s
1280 | # send_server_notice_to_guests: True
1281 | # block_events_error: >-
1282 | # To continue using this homeserver you must review and agree to the
1283 | # terms and conditions at %(consent_uri)s
1284 | # require_at_registration: False
1285 | # policy_name: Privacy Policy
1286 | #
1287 |
1288 |
1289 |
1290 | # Local statistics collection. Used in populating the room directory.
1291 | #
1292 | # 'bucket_size' controls how large each statistics timeslice is. It can
1293 | # be defined in a human readable short form -- e.g. "1d", "1y".
1294 | #
1295 | # 'retention' controls how long historical statistics will be kept for.
1296 | # It can be defined in a human readable short form -- e.g. "1d", "1y".
1297 | #
1298 | #
1299 | #stats:
1300 | # enabled: true
1301 | # bucket_size: 1d
1302 | # retention: 1y
1303 |
1304 |
1305 | # Server Notices room configuration
1306 | #
1307 | # Uncomment this section to enable a room which can be used to send notices
1308 | # from the server to users. It is a special room which cannot be left; notices
1309 | # come from a special "notices" user id.
1310 | #
1311 | # If you uncomment this section, you *must* define the system_mxid_localpart
1312 | # setting, which defines the id of the user which will be used to send the
1313 | # notices.
1314 | #
1315 | # It's also possible to override the room name, the display name of the
1316 | # "notices" user, and the avatar for the user.
1317 | #
1318 | #server_notices:
1319 | # system_mxid_localpart: notices
1320 | # system_mxid_display_name: "Server Notices"
1321 | # system_mxid_avatar_url: "mxc://server.com/oumMVlgDnLYFaPVkExemNVVZ"
1322 | # room_name: "Server Notices"
1323 |
1324 |
1325 |
1326 | # Uncomment to disable searching the public room list. When disabled
1327 | # blocks searching local and remote room lists for local and remote
1328 | # users by always returning an empty list for all queries.
1329 | #
1330 | #enable_room_list_search: false
1331 |
1332 | # The `alias_creation` option controls who's allowed to create aliases
1333 | # on this server.
1334 | #
1335 | # The format of this option is a list of rules that contain globs that
1336 | # match against user_id, room_id and the new alias (fully qualified with
1337 | # server name). The action in the first rule that matches is taken,
1338 | # which can currently either be "allow" or "deny".
1339 | #
1340 | # Missing user_id/room_id/alias fields default to "*".
1341 | #
1342 | # If no rules match the request is denied. An empty list means no one
1343 | # can create aliases.
1344 | #
1345 | # Options for the rules include:
1346 | #
1347 | # user_id: Matches against the creator of the alias
1348 | # alias: Matches against the alias being created
1349 | # room_id: Matches against the room ID the alias is being pointed at
1350 | # action: Whether to "allow" or "deny" the request if the rule matches
1351 | #
1352 | # The default is:
1353 | #
1354 | #alias_creation_rules:
1355 | # - user_id: "*"
1356 | # alias: "*"
1357 | # room_id: "*"
1358 | # action: allow
1359 |
1360 | # The `room_list_publication_rules` option controls who can publish and
1361 | # which rooms can be published in the public room list.
1362 | #
1363 | # The format of this option is the same as that for
1364 | # `alias_creation_rules`.
1365 | #
1366 | # If the room has one or more aliases associated with it, only one of
1367 | # the aliases needs to match the alias rule. If there are no aliases
1368 | # then only rules with `alias: *` match.
1369 | #
1370 | # If no rules match the request is denied. An empty list means no one
1371 | # can publish rooms.
1372 | #
1373 | # Options for the rules include:
1374 | #
1375 | # user_id: Matches agaisnt the creator of the alias
1376 | # room_id: Matches against the room ID being published
1377 | # alias: Matches against any current local or canonical aliases
1378 | # associated with the room
1379 | # action: Whether to "allow" or "deny" the request if the rule matches
1380 | #
1381 | # The default is:
1382 | #
1383 | #room_list_publication_rules:
1384 | # - user_id: "*"
1385 | # alias: "*"
1386 | # room_id: "*"
1387 | # action: allow
1388 |
1389 |
1390 | # Server admins can define a Python module that implements extra rules for
1391 | # allowing or denying incoming events. In order to work, this module needs to
1392 | # override the methods defined in synapse/events/third_party_rules.py.
1393 | #
1394 | # This feature is designed to be used in closed federations only, where each
1395 | # participating server enforces the same rules.
1396 | #
1397 | #third_party_event_rules:
1398 | # module: "my_custom_project.SuperRulesSet"
1399 | # config:
1400 | # example_option: 'things'
1401 |
1402 |
1403 | ## Opentracing ##
1404 |
1405 | # These settings enable opentracing, which implements distributed tracing.
1406 | # This allows you to observe the causal chains of events across servers
1407 | # including requests, key lookups etc., across any server running
1408 | # synapse or any other other services which supports opentracing
1409 | # (specifically those implemented with Jaeger).
1410 | #
1411 | opentracing:
1412 | # tracing is disabled by default. Uncomment the following line to enable it.
1413 | #
1414 | #enabled: true
1415 |
1416 | # The list of homeservers we wish to send and receive span contexts and span baggage.
1417 | # See docs/opentracing.rst
1418 | # This is a list of regexes which are matched against the server_name of the
1419 | # homeserver.
1420 | #
1421 | # By defult, it is empty, so no servers are matched.
1422 | #
1423 | #homeserver_whitelist:
1424 | # - ".*"
1425 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module devture-email2matrix
2 |
3 | go 1.12
4 |
5 | require (
6 | github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef // indirect
7 | github.com/euskadi31/go-service v1.4.0
8 | github.com/flashmob/go-guerrilla v1.6.1
9 | github.com/go-sql-driver/mysql v1.4.1 // indirect
10 | github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f // indirect
11 | github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba // indirect
12 | github.com/jhillyerd/enmime v0.9.3
13 | github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
14 | github.com/mattn/go-runewidth v0.0.13 // indirect
15 | github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
16 | github.com/sirupsen/logrus v1.8.1
17 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
18 | golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a // indirect
19 | google.golang.org/appengine v1.6.7 // indirect
20 | gopkg.in/russross/blackfriday.v2 v2.1.0
21 | )
22 |
23 | replace gopkg.in/russross/blackfriday.v2 => github.com/russross/blackfriday/v2 v2.0.1
24 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef h1:2JGTg6JapxP9/R33ZaagQtAM4EkkSYnIAlOG5EI8gkM=
2 | github.com/asaskevich/EventBus v0.0.0-20200907212545-49d423059eef/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII=
3 | github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a h1:MISbI8sU/PSK/ztvmWKFcI7UGb5/HQT7B+i3a2myKgI=
4 | github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a/go.mod h1:2GxOXOlEPAMFPfp014mK1SWq8G8BN8o7/dfYqJrVGn8=
5 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8 | github.com/euskadi31/go-service v1.4.0 h1:Wz5pR7osrSw+jGOkX+KZ3TxIIVrAqm/o8FB9T00V+E0=
9 | github.com/euskadi31/go-service v1.4.0/go.mod h1:Ug06GLlnDDvnMXc9+nkyitFYa6qdMHZp9vMwFUWE1uU=
10 | github.com/flashmob/go-guerrilla v1.6.1 h1:MLkqzRFUJveVAWuQ3s2MNPTAWbvXLt8EFsBoraS6qHA=
11 | github.com/flashmob/go-guerrilla v1.6.1/go.mod h1:ZT9TRggRsSY4ZVndoyx8TRUxi3tM/nOYtKWKDX94H0I=
12 | github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
13 | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
14 | github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
15 | github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
16 | github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
17 | github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f h1:3BSP1Tbs2djlpprl7wCLuiqMaUh5SJkkzI2gDs+FgLs=
18 | github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
19 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
20 | github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
21 | github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba h1:QFQpJdgbON7I0jr2hYW7Bs+XV0qjc3d5tZoDnRFnqTg=
22 | github.com/jaytaylor/html2text v0.0.0-20211105163654-bc68cce691ba/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
23 | github.com/jhillyerd/enmime v0.9.3 h1:XKqSbnX3AV+MbzM2NnhRlO6BBa123sPTdwtGl2pySik=
24 | github.com/jhillyerd/enmime v0.9.3/go.mod h1:S5ge4lnv/dDDBbAWwtoOFlj14NHiXdw/EqMB2lJz3b8=
25 | github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
26 | github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
27 | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
28 | github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
29 | github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
30 | github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
31 | github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
32 | github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
33 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
34 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
35 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
36 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
37 | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
38 | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
39 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
40 | github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
41 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
42 | github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
43 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
44 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
45 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
46 | github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
47 | github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
48 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
49 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
50 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
51 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
52 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
53 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
54 | golang.org/x/net v0.0.0-20210501142056-aec3718b3fa0/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
55 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk=
56 | golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
57 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
58 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
59 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
60 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
61 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
62 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
63 | golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a h1:ppl5mZgokTT8uPkmYOyEUmPTr3ypaKkg5eFOGrAmxxE=
64 | golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
65 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
66 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
67 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
68 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
69 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
70 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
71 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
72 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
73 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
74 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
75 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
76 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
77 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
78 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
79 |
--------------------------------------------------------------------------------