Compare commits
2 Commits
2585f58c69
...
45f1efb731
Author | SHA1 | Date |
---|---|---|
Arthur POULET | 45f1efb731 | |
Arthur POULET | f10340a597 |
|
@ -1,5 +1,6 @@
|
|||
.env
|
||||
.env*
|
||||
*.db
|
||||
*.sqlite*
|
||||
README.html
|
||||
.yardoc/
|
||||
bin/db_seed.local
|
||||
|
|
8
Gemfile
8
Gemfile
|
@ -3,19 +3,19 @@
|
|||
source "https://rubygems.org"
|
||||
|
||||
# Mails proto
|
||||
gem "net-smtp", "~> 0.3.3"
|
||||
gem "net-imap", "~> 0.3.1"
|
||||
gem "net-smtp", "~> 0.3.3"
|
||||
|
||||
# Mail template
|
||||
gem "erb", "~> 3.0"
|
||||
|
||||
# Database
|
||||
gem "sqlite3", "~> 1.5"
|
||||
gem "sequel", "~> 5.62"
|
||||
gem "sqlite3", "~> 1.5"
|
||||
|
||||
# Web
|
||||
gem "sinatra", "~> 3.0"
|
||||
gem "puma", "~> 6.0"
|
||||
gem "sinatra", "~> 3.0"
|
||||
gem "slim", "~> 4.1"
|
||||
|
||||
# Others
|
||||
|
@ -24,6 +24,6 @@ gem "uuid", "~> 2.3"
|
|||
|
||||
# Debug and stuff
|
||||
group :develop do
|
||||
gem "pry", "~> 0.14.1"
|
||||
gem "mocha", "~> 2.0"
|
||||
gem "pry", "~> 0.14.1"
|
||||
end
|
||||
|
|
27
README.md
27
README.md
|
@ -37,6 +37,29 @@ Copy and fill all the env variables in .env
|
|||
cp empty.env .env
|
||||
edit .env
|
||||
|
||||
Here is the list of all the configuration available (sampled in empty.env):
|
||||
|
||||
SMTP_HOST information to connect on the smtp
|
||||
SMTP_PORT
|
||||
SMTP_TLS true or false
|
||||
SMTP_USER
|
||||
SMTP_PASSWORD
|
||||
IMAP_HOST only imap available
|
||||
IMAP_PORT
|
||||
IMAP_TLS
|
||||
IMAP_USER
|
||||
IMAP_PASSWORD
|
||||
SENDER_HOST the domain of the sender field, and the mailinglist addresses
|
||||
SENDER "true" to retrive the true sender, "list" to use the mailing list email
|
||||
else it is a static email address that will alway be used.
|
||||
DB_URL sqlite://db/database.sqlite for instance
|
||||
PORT for WWW accees, not used yet
|
||||
DEBUG true/false
|
||||
CPU_SLEEP slow down the distributor
|
||||
LOG_FILE log stuff in the specified file
|
||||
|
||||
|
||||
|
||||
### Setup the database
|
||||
|
||||
bin/db_migrate
|
||||
|
@ -53,6 +76,10 @@ After deploying it, there are some tools:
|
|||
|
||||
- `bin/db_seed` to generate some data
|
||||
|
||||
### Additional resources
|
||||
|
||||
[How to manage mailinglists](doc/manage_mailinglists.md)
|
||||
|
||||
## Contributing
|
||||
|
||||
### via Gitea
|
||||
|
|
28
Rakefile
28
Rakefile
|
@ -7,6 +7,34 @@ Minitest::TestTask.create(:test) do |t|
|
|||
t.test_globs = ["test/**/test_*.rb"]
|
||||
end
|
||||
|
||||
namespace "db" do
|
||||
desc "Migrate the database to the lasted schema"
|
||||
task "migrate" do
|
||||
load "bin/db_migrate"
|
||||
end
|
||||
|
||||
desc "Initialize database with dumby data"
|
||||
task "dumb_seed" do
|
||||
load "bin/db_seed"
|
||||
end
|
||||
|
||||
desc "Initialize database with local data"
|
||||
task "local_seed" do
|
||||
load "bin/db_seed.local"
|
||||
end
|
||||
|
||||
desc "Reset all tables, schema, data"
|
||||
task "reset" do
|
||||
require_relative "lib/app"
|
||||
$db.tables.each { $db.drop_table _1 }
|
||||
end
|
||||
|
||||
namespace "reset" do
|
||||
task "stuff" do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
task :default => :test
|
||||
|
||||
task default: :test
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# Mailinglist management
|
||||
|
||||
## What are strategies?
|
||||
|
||||
There are 2 types of strategies: registration and moderation.
|
||||
Registration defines how new user can access the list.
|
||||
Moderation defines how user can write on the list.
|
||||
|
||||
### Registration
|
||||
|
||||
- autoregister: writing any email to the mailinglist will add the email of the user to the mailinglist
|
||||
- free: any email can register to the list by sending a "subscribe" email to the list
|
||||
- validated: like free but moderators needs to confirm the email with a "set-permissions" email. the user details are distributed to moderators first.
|
||||
- closed: nobody can register via email
|
||||
|
||||
### Moderation
|
||||
|
||||
- freewrite: anyone registered can distribute emails to the list
|
||||
- restrictedwrite: email needs approval by moderator before distribution. the email details are only distributed to moderators first.
|
||||
|
||||
## How to interact with the list by email ?
|
||||
|
||||
You need to send an email to the list with the subject being an action.
|
||||
Some action can take parameters in the subject or the body.
|
||||
|
||||
Actions are:
|
||||
- set-permissions
|
||||
- validate
|
||||
- refuse
|
||||
- subscribe
|
||||
- unsubscribe
|
||||
- help
|
||||
- list-users
|
||||
- owner
|
||||
|
||||
Parameters are key=value, which are separated with "," in the subject or "new line" in the body.
|
||||
|
||||
### permissions parameters
|
||||
permissions: a permission mask (0=reader, 1=writer, 2=operator, 4=moderator)
|
||||
user-email: the email of the user
|
||||
|
||||
### validate parameters
|
||||
uid: uid of the email
|
|
@ -11,6 +11,7 @@ IMAP_USER=
|
|||
IMAP_PASSWORD=
|
||||
|
||||
SENDER_HOST=machin.fr
|
||||
SENDER=list@machin.fr
|
||||
DB_URL="sqlite://dev.db"
|
||||
|
||||
PORT=10081
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require "uuid"
|
||||
|
||||
class Mailinglist < Sequel::Model($db)
|
||||
SUFFIX_SEPARATOR = ENV["MAILINGLIST_SUFFIX_SEPARATOR"] || "."
|
||||
SUFFIX_SEPARATOR = ENV["MAILINGLIST_SUFFIX_SEPARATOR"] || "+"
|
||||
BASE_USER = ENV["MAILINGLIST_BASE_USER"] || "mailinglist"
|
||||
HOST = ENV["MAILINGLIST_HOST"]
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class Protocols::Imap
|
|||
attr_reader :imap if $debug
|
||||
|
||||
def reset!
|
||||
@imap = Net::IMAP.new(ENV["IMAP_HOST"], ENV["IMAP_PORT"], ssl: true)
|
||||
@imap = Net::IMAP.new(ENV["IMAP_HOST"], port: ENV["IMAP_PORT"], ssl: true)
|
||||
@imap.authenticate('PLAIN', ENV["IMAP_USER"], ENV["IMAP_PASSWORD"])
|
||||
ALL_INBOXES.each do
|
||||
$logger.info "Try to create inbox #{_1}"
|
||||
|
@ -31,10 +31,18 @@ class Protocols::Imap
|
|||
# Fetch the next incomming email as a Protocols::Mail.
|
||||
#
|
||||
# @return [Protocols::Mail]
|
||||
def fetch_next_unseen(inbox:)
|
||||
uid = search_unseen(inbox:).first
|
||||
return nil if uid.nil?
|
||||
def fetch_next_unseen(inbox:, max_tries: 2)
|
||||
return $logger.error("fetch_next_unseen reached max_tries_limit") if max_tries == 0
|
||||
|
||||
begin
|
||||
uid = search_unseen(inbox:).first
|
||||
rescue IOError => e
|
||||
$logger.warn e.message
|
||||
reset!
|
||||
return fetch_next_unseen(inbox:, max_tries: max_tries - 1)
|
||||
end
|
||||
|
||||
return nil if uid.nil?
|
||||
fetch(uid:, inbox:)
|
||||
end
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@ class Protocols::Mail
|
|||
HEADERS_KEEP = %w[
|
||||
Content-Type Content-Transfer-Encoding MIME-Version
|
||||
].freeze
|
||||
HEADERS_KEEP_WITH_ORIGINAL = HEADERS_KEEP + %w[Message-ID User-Agent From To Subject Subject Date In-Reply-To References]
|
||||
HEADERS_KEEP_WITH_ORIGINAL = HEADERS_KEEP + %w[Message-ID User-Agent From To Subject Subject Date In-Reply-To
|
||||
References]
|
||||
USER_AGENT = "Ruby/#{RUBY_VERSION} (#{RUBY_PLATFORM}) Mailinglist.rb/1.0".freeze
|
||||
SENDER = ENV["SENDER"]
|
||||
|
||||
# @params imap_mail is any element outputed in the returned array of
|
||||
# Net::IMAP#fetch, and must contains some attributes:
|
||||
|
@ -72,7 +74,16 @@ class Protocols::Mail
|
|||
["Errors-To", list.email],
|
||||
["To", dest.email],
|
||||
["From", "\"#{@from_name}\" (via #{list.name}) <#{@from}>"],
|
||||
["Sender", @from],
|
||||
[
|
||||
"Sender",
|
||||
if SENDER == "true"
|
||||
@from
|
||||
elsif SENDER == "list"
|
||||
list.email
|
||||
else
|
||||
SENDER
|
||||
end
|
||||
],
|
||||
["Date", Time.now.strftime(DATE_FORMAT)],
|
||||
["List-Id", "<#{list.email}>"],
|
||||
["List-Post", "<mailto:#{list.email}>"],
|
||||
|
|
|
@ -61,6 +61,9 @@ class Protocols::Smtp
|
|||
$logger.warn e.message
|
||||
reset_smtp_client!
|
||||
send_message_safe(*raw, max_tries: max_tries - 1)
|
||||
rescue => e
|
||||
$logger.error e.full_message
|
||||
reset_smtp_client!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue