Skip to content

Simple .NET application converting "e-mails" to REST API calls

License

Notifications You must be signed in to change notification settings

nicolaihenriksen/SmtpToRestService

Repository files navigation

SmtpToRest

Build NuGet-Themes

Simple .NET application converting "e-mails" to REST API calls. Can be executed as a Docker container, as a Windows Service or self-hosted using the standard .NET host builder pattern.

I created this application because I needed to trigger some REST API services in my home automation system when certain types of motion events happened on my CCTV cameras. Although my cameras are ONVIF compliant, they do no not expose these motion events via the ONVIF Profile S, and thus are unavailable in my home automation system integration.

My workaround for this problem was to configure the cameras to "send an e-mail" when the desired motion events occurred, but instead of using my normal SMTP server to send the email, I configured the cameras to use the SMTP service hosted by the code in this repository instead. This service then converts those "e-mails" into the desired REST API calls I need in my home automation system.

The project has since then become a hobby project where I am experimenting with adding Docker support, CI/CD pipelines and other fun stuff.

Configuration

The sample configuration below illustrates the current possibilites.

{
  "smtpHost": "localhost",
  "smtpPorts": [ 25, 587 ],
  "apiToken": "<place your API token here if needed>",
  "endpoint": "https://jsonplaceholder.typicode.com/",
  "httpMethod": "GET",
  "smtpRelay": {
    "enabled": true,
    "host": "smtp.gmail.com",
    "port": 587,
    "authenticate": true,
    "username": "myprimaryuser@gmail.com",
    "password": "mypassword"
  },
  "mappings": [
    {
      "key": "list.posts@somedomain.com",
      "service": "posts",
      "smtpRelay": {
        "enabled": false
      }
    },
    {
      "key": "add.post@somedomain.com",
      "customHttpMethod": "POST",
      "service": "posts",
      "content": {
        "title": "Test post",
        "body": "Test post body sent from $(from)",
        "userId": 1
      }
    },
    {
      "key": "add.get@somedomain.com",
      "customApiToken": "eyJ0eXAiOiJKV1QLKiFhbGciOiJIUzI1NiJ9.eyJpc3MieJoLYjY0ZTZkMThh...<cutoff>",
      "customEndpoint": "https://somerestapi.com/",
      "service": "posts",
      "queryString": "title=Test+post&body=Test+post+body&userId=1",
      "smtpRelay": {
        "enabled": true,
        "host": "192.168.1.100",
        "port": 25,
        "authenticate": false
      }
    }
  ]
}

Property Description
smtpHost Optional
Defines the host (endpoint) where the SMTP server will be listening. Defaults to "localhost".
Note Does not support runtime updates
smtpPorts Optional
Defines ports the SMTP server will be listening on. Defaults to ports 25 and 587.
Note Does not support runtime updates
apiToken Optional
Defines the API token used for mappings (unless overridden in the mapping). Should be set if the REST service requires you to provide an API key.
endpoint Required - if "customEndpoint" not set on mapping
Defines the common endpoint used for mappings (unless overridden in the mapping).
httpMethod Optional - defaults to "GET"
Defines the common HTTP method to use for mappings (unless overridden in the mapping).
mappings Optional (but boring service if omitted)
Defines a list of mappings (see below).
smtpRelay Optional
Defines the shared configuration for SMTP relay used to send/relay the e-mail (see below).

Mapping

A mapping is what the services uses to convert an e-mail into a REST API call. If a mapping is found where the key of the mapping matches the to address of the e-mail, the REST API call defined by the mapping is invoked.

Property Description
customHttpClientName Optional
HTTP Client name used for this particular mapping. Should be set if you have injected your own named IHttpClient into the DI container.
customApiToken Optional
API token used for this particular mapping. Should be set if the REST service requires you to provide an API key.
customEndpoint Optional
Defines the endpoint for this particular mapping.
customHttpMethod Optional
Defines the HTTP method for this particular mapping.
service Required
Defines the path appended to the enpoint to complete the URL.
queryString Optional
Defines a query string to be appended to the URL (used in GET requests).
content Optional
Defines the content (often times a JSON object) to be set as the content of the request (often used in POST requests).
smtpRelay Optional
Defines the configuration for mapping-specific SMTP relay used to send/relay the e-mail (see below).

SmtpRelay

The SMTP relay is used to forward the e-mail to another SMTP server. This is useful if you want to forward the e-mail to another service/recipient. All values are optional and will fall-back to the default from the configuration if omitted in the mapping.

Property Description
host Optional
Defines the hostname or IP address of the SMTP server.
port Optional
Defines the port used to connect to the SMTP server.
authenticate Optional
Defines whether or not authentication should be used when connecting to the SMTP server.
username Optional
Defines the username to use for authentication.
password Optional
Defines the password to use for authentication.

Token replacements

The following tokens can be used in the configuration and will be replaced with the corresponding values from the e-mail:

Token Description
$(from) The The (first) sender address
$(to) The (first) recipient address
$(body) The (string) body of the e-mail

Each token can be applied as shown above to simply extract the token value in its entirety, or alternatively the token syntax below can be used to narrow down the selection.

Name Syntax Example Description
Substring $(<token>){<startIndex>} $(body){15} Will take the substring of the token starting at the provided <startIndex>.
Substring and length $(<token>){<startIndex>,<length>} $(body){15,10} Will take the substring of the token starting at the provided <startIndex> and <length> characters forward.
Substring from index of string $(<token>){[<stringToFind>]} $(body){[hello]} Will take the substring of the token starting at index of the provided <stringToFind>.
Substring from index of string with offset $(<token>){[<stringToFind>]+<offset>} $(body){[hello]+10} Will take the substring of the token starting at index of the provided <stringToFind> using the provided offset. Note the offset can also be negative.
Substring from index of string and length $(<token>){[<stringToFind>],<length>} $(body){[hello],40} Will take the substring of the token starting at index of the provided <stringToFind> and <length> characters forward.
Substring from index of string to index of another string $(<token>){[<stringToFind1>],[<stringToFind2>]} $(body){[hello],[world]} Will take the substring of the token starting at index of the provided <stringToFind1> up until the inded of the provided <stringToFind2>.

Note that the list above is not exhaustive. It demonstrates the different elements of the syntax that can be applied, and these can be mixed and matched for the desirable "from" and "length"/"to" combination.


Install as Docker container

See SmtpToRest.Docker for more information.

Install as Windows Service

See SmtpToRest.WindowsService for more information.

Self-host (e.g. using GenericHost)

See SmtpToRest for more information.


Credits

In order to minimize my workload, I used the following Nuget packages:

Package Author Usage
SmtpServer Cain O'Sullivan I use this package to self-host an SMTP server.
MailKit Jeffrey Stedfast I use this package to convert a byte-stream into a strongly typed MIME object and as an SMTP relay to forward e-mail messages.

About

Simple .NET application converting "e-mails" to REST API calls

Resources

License

Stars

Watchers

Forks

Packages

No packages published