Unofficial Rust library for the SendGrid API

Overview

sendgrid-rs

Unofficial Rust library for the SendGrid API.

Build Status

This crate requires Rust 1.15 or higher as it uses a crate that has a custom derive implementation.

sendgrid-rs implements all of the functionality of other supported SendGrid client libraries. To use sendgrid-rs you must first create a SendGrid account and generate an API key. To create an API key for your SendGrid account, use the account management interface or see the SendGrid API Documentation.

sendgrid-rs is available on crates.io and can be included in your Cargo.toml as follows:

[dependencies]
sendgrid = "X.X.X"

Build Dependencies

This library utilises reqwest. Follow the instructions on the reqwest README in order to enable sending HTTPS requests to the SendGrid API.

Features

You can take advantage of a couple features for the crate. To enable the asynchronous send function, you can use the async flag. To enable the rustls TLS feature, use the rustls flag.

Example

An example of using this library can be found in the examples directory. This example code expects to find your SendGrid API key in the process environment. In shells such as Bash or ZSH this can be set as follows:

export SENDGRID_API_KEY="SG.my.api.key"

Documentation

Documentation

Please don't hesitate to contact me at the email listed in my profile. I will try to help as quickly as I can. If you would like to contribute, contact me as well.

Mentions

Thanks to meehow for their contributions.

Thanks to richo for their improvements to the V2 API.

License

MIT

Comments
  • refactor mail

    refactor mail

    Heyo,

    Feel free to push back on any/everything in here! I made a bunch of breaking changes, but I think with decent justification.

    The switch from String's to &str is fairly important to me. I have an application which can't move ownership of it's metadata around, and copies get expensive pretty quickly.

    The builder stuff isn't particularly important at all, but it does let you avoid having to make your Mail objects mut which is nice, and this is also a super common pattern in rust. The more common pattern is to have a MailBuilder which doesn't let you have a concrete Mail until you ::build(), I can implement that if you have the appetite but I wanted to get your thoughts on this.

    We could also save a ton of copypasting by using a macro to generate these methods (ala https://github.com/richo/archiver/blob/master/src/pushover.rs#L68-L74). Again, I'll happily implement that if you like.

    opened by richo 10
  • v3: Fix dynamic template data assignment

    v3: Fix dynamic template data assignment

    The dynamic template data was overriding the headers and causing the personalizations to be lost. Besides fixing the assignment, we renamed the argument to be more meaningful.

    Signed-off-by: Otavio Salvador [email protected]

    opened by otavio 7
  • Authorization failed

    Authorization failed

    I made the same example using sendgrid-rs and sendgrid-nodejs

    const sgMail = require("@sendgrid/mail");
    sgMail.setApiKey(
        "xxxx"
    );
    const msg = {
        to: "[email protected]",
        from: "[email protected]", // Use the email address or domain you verified above
        subject: "Sending with Twilio SendGrid is Fun",
        text: "and easy to do anywhere, even with Node.js",
        html: "<strong>and easy to do anywhere, even with Node.js</strong>",
    };
    //ES6
    sgMail.send(msg).then(
        () => {},
        error => {
            console.error(error);
    
            if (error.response) {
                console.error(error.response.body);
            }
        }
    )
    //ES8
    ;(async () => {
        try {
            await sgMail.send(msg);
        } catch (error) {
            console.error(error);
    
            if (error.response) {
                console.error(error.response.body);
            }
        }
    })();
    
    
    use std::collections::HashMap;
    
    use sendgrid::errors::SendgridError;
    use sendgrid::v3::*;
    
    #[tokio::main]
    async fn main() -> Result<(), ()> {
        println!("Hello, world!");
        let mut cool_header = HashMap::new();
        cool_header.insert(String::from("x-cool"), String::from("indeed"));
        cool_header.insert(String::from("x-cooler"), String::from("cold"));
    
        let p = Personalization::new()
            .add_to(Email::new().set_email("[email protected]"))
            .add_headers(cool_header);
    
        let m = Message::new()
            .set_from(Email::new().set_email("[email protected]"))
            .set_subject("Subject")
            .add_content(
                Content::new()
                    .set_content_type("text/html")
                    .set_value("Test"),
            )
            .add_personalization(p);
    
        // let mut env_vars = ::std::env::vars();
        // let api_key = env_vars.find(|v| v.0 == "SG_API_KEY").unwrap();
        let sender = Sender::new(
    "xxxx"
        );
        let resp = sender.send(&m).await.unwrap();
        println!("status: {}", resp.status());
        Ok(())
    }
    
    
    opened by GopherJ 6
  • when SG returns error, library happily returns success

    when SG returns error, library happily returns success

    Hey @gsquire, I've tried to send message and it returned Ok with the following error:

    {"errors":[{"message":"If present, text/plain must be first, followed by text/html, followed by any other content.","field":"content","help":null}]}
    

    I wonder if SG returns successful status code in this case?

    opened by kanekv 5
  • Compile with async feature flag

    Compile with async feature flag

    Hello,

    I've added the option to build sendgrid-rs with the async client from reqwest. This allows you to use sendgrid-rs with async frameworks like tokio, actix, etc.

    Regards, Peita

    opened by peitalin 4
  • Migrate from error chain to failure

    Migrate from error chain to failure

    Let me know what you think. This obviously breaks some interfaces, I think the only real question is whether you want to return failure::Errors. Currently there's basically a roundtrip, since all the errors we wrap implement Fail.

    cc #29

    opened by richo 4
  • Fix documentation, make v2 async

    Fix documentation, make v2 async

    Hi,

    I've made a PR that changes a couple of things to this library:

    • I've added #![deny(missing_docs)] to the crate, and documented all public items in the crate,
    • I've modified the macro that generates the setters for the Mail struct, so that it now correctly displays the provided documentation,
    • I've added a From<(&str, &str)> impl to the destination struct, to more succinctly be able to constrIuct this type,
    • I found a couple of use serde_json; occurrences, but they don't do anything since serde_json is a dependency, and thus always in scope,
    • I added the native-tls feature, which is enabled by default, but that users can switch off when they use RusTLS if they don't want to link OpenSSL,
    • I made the v2 api also switch to async reqwest when the async feature flag is enabled.

    Let me know if I need to change anything!

    opened by ThouCheese 3
  • add response text for easier debug

    add response text for easier debug

    I tried using this with the new change and it turns out life is really hard when you can't know WHY the status code is not a success, so here is a follow-up PR.

    opened by ruseinov 3
  • V3 Builder

    V3 Builder

    This is a start of the migration to the builder pattern for the V3 module. The V2 module should be considered deprecated since V3 has been out for years now and is the preferred way to send messages using SendGrid's API. Unless there is a strong objection, I will mark it as deprecated.

    Closes #30 Closes #37 Closes #38

    CC @Ten0 @otavio for review. The example has been updated to showcase the new API for now.

    opened by gsquire 3
  • Rust 2018 update causing V3Sender to result in 415 response

    Rust 2018 update causing V3Sender to result in 415 response

    When updating a project to Rust 2018, a previously working sendgrid email setup returns a 415 StatusCode (Unsupported Media Type).

    When using sendgrid-rs 0.7.2 the the V3Sender content-type header looks like...

    headers.insert(
        header::CONTENT_TYPE,
        HeaderValue::from_static("application/x-www-form-urlencoded"),
    );
    

    However, the master branch has changed the content type to application/json which causes the emails to send correctly.

    It looks like the master branch can be deployed as it is?

    opened by leanrob 3
  • Return message id from v3 send API

    Return message id from v3 send API

    I need to access the message id returned by the v3 send API, but couldn't see a way to do it. Am I missing something?

    To get something working in the meantime, I ended up making a branch that returns it instead of the response status, getting the value out of the X-Message-Id header. Is there some version of that change that would be worth me tidying up and opening as a PR?

    opened by philbooth 3
  • Type system is not leveraged to avoid mistakes when building sendgrid requests

    Type system is not leveraged to avoid mistakes when building sendgrid requests

    The library provides lots of way to build Sendgrid queries that have zero chance to succeed: Examples:

    sender.send(&Message::new())?;
    
    sender.send(&Message::new()
    			.set_from(self.from.clone())
    			.set_subject(subject)
    			.add_personalization(Personalization::new().add_to(Email::new().set_email(to_email)))
    			.add_content(Content::new().set_value(body)))?;
    
    sender.send(&Message::new()
    			.set_subject(subject)
    			.add_personalization(Personalization::new().add_to(Email::new().set_email(to_email)))
    			.add_content(Content::new().set_content_type("text/html").set_value(body)))?;
    
    sender.send(&Message::new()
    			.set_from(self.from.clone())
    			.add_personalization(Personalization::new().add_to(Email::new().set_email(to_email)))
    			.add_content(Content::new().set_content_type("text/html").set_value(body)))?;
    
    sender.send(&Message::new()
    			.set_from(self.from.clone())
    			.set_subject(subject)
    			.add_content(Content::new().set_content_type("text/html").set_value(body)))?;
    
    sender.send(&Message::new()
    			.set_from(self.from.clone())
    			.set_subject(subject)
    			.add_personalization(Personalization::new().add_to(Email::new().set_email(to_email)))
    			.add_content(Content::new().set_content_type("text/htlm").set_value(body)))?;
    

    It's already been several times we've gotten trapped by this, resulting in broken deployed software.

    Given the amount of fields that are mandatory/have restricted values, there should only be, as much as possible, constructors that respect the Sendgrid constraints.

    e.g.:

    sender.send(Message::new(
       "[email protected]",
       "[email protected]",
       Content::html("subject", "<strong>body</strong>"),
    )
    

    where Content could be:

    #[serde(untagged)] // and flattened into the message
    pub enum Content<'a> {
        SubjectAndBody {
            subject: &'a str,
            body: Body<'a>,
        }
        Template {
            // If I understand correctly https://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/index.html
            // specifying a template id makes subject and body optional
            template_id: &'a str,
            subject: Option<&'a str>,
            body: Option<Body<'a>>,
        }
    }
    
    pub struct Body<'a> {
        content_type: ContentType,
        body: &'a str,
    }
    
    pub enum ContentType {
        Html,
        PlainText,
    }
    

    etc.

    I feel like providing typing for an API is be the whole point of this kind of library. Otherwise if I'm going to have to read the Sendgrid spec anyway to figure which fields are mandatory and where I should put them, I almost might as well write my own serde SDK.

    opened by Ten0 5
a mailer library for Rust

lettre A mailer library for Rust NOTE: this readme refers to the 0.10 version of lettre, which is still being worked on. The master branch and the alp

lettre 1.3k Jan 4, 2023
Rust library to parse mail files

mailparse A simple parser for MIME email messages. API The primary entry point for this library is the following function: parse_mail(&[u8]) -> Re

Kartikaya Gupta (kats) 150 Dec 27, 2022
Fast and robust e-mail parsing library for Rust

mail-parser mail-parser is an e-mail parsing library written in Rust that fully conforms to the Internet Message Format standard (RFC 5322), the Multi

Stalwart Labs 158 Jan 1, 2023
mail-builder is a flexible e-mail builder library written in Rust that generates RFC5322 compliant e-mail messages

mail-builder mail-builder is a flexible e-mail builder library written in Rust that generates RFC5322 compliant e-mail messages. The library has full

Stalwart Labs 37 Dec 19, 2022
An ESMTP server library written in Rust.

rs-smtp An ESMTP server library written in Rust. Features ESMTP client & server implementing RFC 5321 Support for SMTP AUTH and PIPELINING UTF-8 suppo

DUNEF 3 Apr 15, 2023
E-mail delivery library for Rust with DKIM support

mail-send mail-send is a Rust library to build, sign and send e-mail messages via SMTP. It includes the following features: Generates e-mail messages

Stalwart Labs 165 Oct 23, 2023
新しい IMAP client in Rust

新しい IMAP client 新しい (atarashii/new) IMAP client in Rust. It supports plain and secure connections. In progress It's under development... Usage Put thi

Alex Maslakov 39 Sep 13, 2020
Implementation of mjml in rust

MRML Introduction This project is a reimplementation of the nice MJML markup language in Rust. How to use it use mrml; fn main() { match mrml::to

Jérémie Drouet 228 Dec 28, 2022
Rust implementation of catapulte email sender

Catapulte What is catapulte? Catapulte is an open source mailer you can host yourself. You can use it to quickly catapult your transactionnal emails t

Jérémie Drouet 108 Dec 14, 2022
📫Himalaya: CLI email client written in Rust.

??Himalaya: CLI email client written in Rust.

Clément DOUIN 2.1k Jan 7, 2023
Check if an email address exists without sending any email, written in Rust.

Check if an email address exists without sending any email, written in Rust.

Reacher 3.5k Dec 31, 2022
A mail suite written in rust meant to be easy to use.

Erooster A mail suite written in rust meant to be easy to use. Getting started Currently the setup is quite rough. You need some certificates for your

Marcel 33 Dec 19, 2022
A rewrite of the server side parts of emersion/go-smtp package into rust.

rust-smtp-server A rust smtp server library. It's mainly a rewrite of the server side parts of the emersion/go-smtp library. Features Usage Add this t

Nick Westendorf 3 Apr 26, 2023
A small unofficial library to send emails using Sendgrid.

sendgrid_thin A thin wrapper around the SendGrid V3 API. It does not use the crate tokio or hyper and is therefore very lightweight and do not interfe

Reinaldo Rozato Junior 3 Nov 17, 2022
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
An unofficial client library for the fuzz-introspector API.

fuzz-introspector-client An unofficial client library for the fuzz-introspector API. Quickstart Add package as a dependency; cargo add fuzz-introspect

Nathaniel Brough 4 Nov 25, 2023
Boursorama / BoursoBank unofficial API and CLI

Bourso CLI This app aims to be a simple CLI powered by Bourso API to log in to your BoursoBank/Boursorama account and achieve some basic tasks. The fi

Azerpas 4 Nov 20, 2023
An (unofficial) Rust library for querying db-ip.com data

db_ip An (unofficial) library for querying db-ip.com CSV databases in safe Rust. This library is not affiliated with or endorsed by db-ip.com. Be advi

Finn Bear 4 Dec 2, 2022
An unofficial and incomplete no_std Rust library for implementing the ElectricUI Binary Protocol

An unofficial and incomplete no_std Rust library for implementing the ElectricUI Binary Protocol

Jon 2 Mar 29, 2022
Unofficial python bindings for the rust llm library. 🐍❤️🦀

llm-rs-python: Python Bindings for Rust's llm Library Welcome to llm-rs, an unofficial Python interface for the Rust-based llm library, made possible

Lukas Kreussel 7 May 20, 2023