DEV Community

Cover image for Introducing 'sparkpost' a Rust Crate for email API
Harry Gill
Harry Gill

Posted on • Updated on

Introducing 'sparkpost' a Rust Crate for email API

Rust is an enjoyable language, and I have been experimenting with it for a some time. I started with creating a few web servers using different crates including rocket and actix. I needed to use an email api to send messages from the backend to either myself or the user.

I have used Sparkpost as an email service for such purpose in some of my nodejs apps. Having not found any rust API lib for it I decided to create one for myself. It is available on https://crates.io/crates/sparkpost.

Current implementation includes transmission api only. That allows you to send emails with metadata, templates and other features.

Here is a complete example of how to use the lib
[dependencies]
sparkpost="0.4"
serde_json="1.0"
serde_derive = "1.0"
serde = "1.0"
chrono = { version = "0.4", features = ["serde"] }
dotenv = "0.13"
// main.rs

#[macro_use]
extern crate serde_derive;
extern crate chrono; // for setting dateTime option to an email
extern crate dotenv; // optional- to read api key from .env file
extern crate serde;
extern crate sparkpost;

use chrono::prelude::*;
use sparkpost::transmission::{
  Attachment, EmailAddress, Message, Options, Recipient, Transmission, TransmissionResponse,
};


// this could be any Type to replace vlaues in sparkpost template
// only requirement is that it implements Serialize from serde
#[derive(Debug, Serialize)]
struct Data {
  name: String,
}

#[allow(unused)]
fn get_api_key() -> String {
  use dotenv::dotenv;
  use std::env;
  dotenv().ok();
  env::var("SPARKPOST_API_KEY").expect("SPARKPOST_API_KEY must be set")
}

fn main() {
  // for eu servers use 
  // let tm = Transmission::new_eu(get_api_key());
  let tm = Transmission::new(get_api_key());


  // new email message with sender name and email
  let mut email = Message::new(EmailAddress::new(
    "marketing@example.sink.sparkpostmail.com",
    "Example Company",
  ));

  let options = Options {
    open_tracking: true,
    click_tracking: true,
    transactional: false,
    sandbox: false,
    inline_css: false,
    start_time: Some(Utc.ymd(2019, 1, 1).and_hms(0, 0, 0)),
  };

  // recipient with substitute data for the template
  let recipient = Recipient::with_substitution(
    EmailAddress::new("bob@company.com", "Bob"),
    Data { name: "Bob".into() },
  );

  let attachment = Attachment {
       file_type: "image/png".into(),
       name: "AnImage.png".into(),
       // data is base64 encoded string
       data: "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAmCC".into(),
   };

  // complete the email message with details
  email
    .add_recipient(recipient)
    .add_attachment(attachment)
    .options(options)
    .campaign_id("marketing_blitz")
    .subject("My Awesome email 😎")
    .html("<h1>hello {name}</h1>")
    .text("hello {name}");

  let result = tm.send(&email);

  match result {
    Ok(res) => {
      match res {
        TransmissionResponse::ApiResponse(api_res) => {
          println!("API Response: \n {:#?}", api_res);
            assert_eq!(1, api_res.total_accepted_recipients);
            assert_eq!(0, api_res.total_rejected_recipients);
        }
        TransmissionResponse::ApiError(errors) => {
          println!("Response Errors: \n {:#?}", &errors);
        }
      }
    }
    Err(error) => {
      println!("error \n {:#?}", error);
    }
  }
}


As I mentioned above that there are many features that are lacking i.e. saving and retrieving templates and recipient list etc. Reason is that I don't use those features for now. If anyone is interested I will be more than happy to help.

Twitter

Originally published on hgill.io

Top comments (0)