Added SMTP_PORT configuration option.

This commit is contained in:
Peter van Nostrand 2018-04-24 12:57:06 -04:00
parent d2911aa349
commit 118923e885
7 changed files with 50 additions and 21 deletions

View File

@ -14,6 +14,7 @@ jsonrpc-core = "8.0.1"
lazy_static = "1.0.0"
lettre = "0.8"
lettre_email = "0.8"
native-tls = "0.1.5"
reqwest = "0.8.5"
serde = "1.0.36"
serde_derive = "1.0.36"

View File

@ -70,6 +70,13 @@ Add a comma-separated list of email address to the "VALIDATORS" config
option in your .env file. These addresses will be sent emails when `poagov`
encounters governance events on the POA blockchain.
*Note* `poagov` forces SMTP email notifcations to be sent over an encrypted
channel, if your SMTP Host does not support TLS or STARTTLS, `poagov` will
panic. You may notice that we default `SMTP_PORT` to port 587 for STARTTLS,
but you may use port 465 for TLS, or any other port that your outgoing
email server is lisening for secure connections. If you require unencrypted
SMTP, submit an issue and I can add it.
# An Explained Example
$ ./target/release/poagov --sokol --earliest -kt --email

View File

@ -8,6 +8,7 @@ SEND_PUSH_NOTIFICATIONS=false
# Email configuration.
SMTP_HOST_DOMAIN=
SMTP_PORT=587
SMTP_USERNAME=
SMTP_PASSWORD=
OUTGOING_EMAIL_ADDRESS=

View File

@ -159,6 +159,7 @@ pub struct Config {
pub validators: Vec<Validator>,
pub avg_block_time: Duration,
pub smtp_host_domain: String,
pub smtp_port: u16,
pub smtp_username: String,
pub smtp_password: String,
pub outgoing_email: String
@ -263,17 +264,16 @@ impl Config {
};
let smtp_host_domain = env::var("SMTP_HOST_DOMAIN").unwrap();
let smtp_port = env::var("SMTP_PORT").unwrap().parse().unwrap();
let smtp_username = env::var("SMTP_USERNAME").unwrap();
let smtp_password = env::var("SMTP_PASSWORD").unwrap();
let outgoing_email = env::var("OUTGOING_EMAIL_ADDRESS").unwrap();
Config {
network, endpoint, contracts, start_block,
send_email_notifications,
send_push_notifications,
validators, avg_block_time,
smtp_host_domain, smtp_username,
smtp_password, outgoing_email
send_email_notifications, send_push_notifications,
validators, avg_block_time, smtp_host_domain,
smtp_port, smtp_username, smtp_password, outgoing_email
}
}
}

View File

@ -15,7 +15,12 @@ lazy_static! {
}
pub fn log_notification(notif: &Notification) {
info!(LOGGER, "notification"; "data" => format!("{:#?}", notif));
let notif_data = match *notif {
Notification::Keys(ref inner) => format!("{:#?}", inner),
Notification::Threshold(ref inner) => format!("{:#?}", inner),
Notification::Proxy(ref inner) => format!("{:#?}", inner)
};
info!(LOGGER, "notification"; "data" => notif_data);
}
pub fn log_email_sent(email: &str) {

View File

@ -8,6 +8,7 @@ extern crate jsonrpc_core;
#[macro_use] extern crate lazy_static;
extern crate lettre;
extern crate lettre_email;
extern crate native_tls;
extern crate reqwest;
extern crate serde;
extern crate serde_json;

View File

@ -1,16 +1,18 @@
use chrono::{DateTime, Utc};
use ethereum_types::Address;
use lettre::{EmailTransport, SmtpTransport};
use lettre::smtp::{self, ConnectionReuseParameters};
use lettre::smtp::{ClientSecurity, ConnectionReuseParameters, SmtpTransportBuilder};
use lettre::smtp::authentication::{Credentials, Mechanism};
use lettre_email::{self, Email, EmailBuilder};
use lettre::smtp::client::net::{ClientTlsParameters, DEFAULT_TLS_PROTOCOLS};
use lettre::smtp::error::Error as BuildSmtpError;
use lettre_email::{Email, EmailBuilder};
use lettre_email::error::Error as BuildEmailError;
use native_tls::TlsConnector;
use config::{Config, ContractType, Network, Validator};
use logging::{log_email_failed, log_email_sent, log_notification};
use rpc::{BallotCreatedLog, BallotType, KeyType, VotingData};
type BuildEmailResult = Result<Email, lettre_email::error::Error>;
#[derive(Debug)]
pub enum Notification {
Keys(KeysNotification),
@ -119,23 +121,35 @@ pub struct Notifier<'a> {
}
impl<'a> Notifier<'a> {
pub fn new(config: &'a Config) -> Result<Self, smtp::error::Error> {
let mailer = if config.send_email_notifications {
let creds = Credentials::new(
pub fn new(config: &'a Config) -> Result<Self, BuildSmtpError> {
let mut notifier = Notifier { config, mailer: None };
if config.send_email_notifications {
let smtp_addr = (config.smtp_host_domain.as_str(), config.smtp_port);
let smtp_tls = {
let mut tls_builder = TlsConnector::builder().unwrap();
tls_builder.supported_protocols(DEFAULT_TLS_PROTOCOLS).unwrap();
let tls = tls_builder.build().unwrap();
let tls_params = ClientTlsParameters::new(config.smtp_host_domain.clone(), tls);
ClientSecurity::Required(tls_params)
};
let smtp_creds = Credentials::new(
config.smtp_username.clone(),
config.smtp_password.clone()
);
let mailer = SmtpTransport::simple_builder(&config.smtp_host_domain)?
let mailer = SmtpTransportBuilder::new(smtp_addr, smtp_tls)?
.connection_reuse(ConnectionReuseParameters::ReuseUnlimited)
.authentication_mechanism(Mechanism::Plain)
.credentials(creds)
.credentials(smtp_creds)
.build();
Some(mailer)
} else {
None
};
Ok(Notifier { config, mailer })
notifier.mailer = Some(mailer);
}
Ok(notifier)
}
pub fn build_notification(&self, log: &BallotCreatedLog, voting_data: &VotingData) -> Notification {
@ -161,7 +175,7 @@ impl<'a> Notifier<'a> {
}
}
fn build_email(&self, validator: &Validator, notif: &Notification) -> BuildEmailResult {
fn build_email(&self, validator: &Validator, notif: &Notification) -> Result<Email, BuildEmailError> {
let body = match *notif {
Notification::Keys(ref inner) => format!("{:#?}\n", inner),
Notification::Threshold(ref inner) => format!("{:#?}\n", inner),