Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Global rule:
* @Bandwidth-Samples/dx
* @Bandwidth-Samples/band-swi @Bandwidth-Samples/band-devx
19 changes: 19 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: 2

updates:
- package-ecosystem: nuget
directory: /AutoRespond
schedule:
interval: monthly
open-pull-requests-limit: 5
ignore:
- dependency-name: "Bandwidth.Sdk"
update-types:
- version-update:semver-minor
- version-update:semver-patch
groups:
dependencies:
patterns:
- "*"
exclude-patterns:
- "Bandwidth.Sdk"
16 changes: 16 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: Test

on:
pull_request:
branches:
- main
schedule:
- cron: "0 9 * * 1"

jobs:
contract-test:
name: Contract Test
uses: Bandwidth-Samples/sample-app-tooling/.github/workflows/csharp.yml@main
with:
sample: messaging-auto-respond
working-directory: AutoRespond
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Bandwidth.Sdk" Version="11.0.0-beta" />
<PackageReference Include="Bandwidth.Sdk" Version="17.3.2" />
</ItemGroup>

</Project>
119 changes: 119 additions & 0 deletions AutoRespond/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
using Bandwidth.Standard.Api;
using Bandwidth.Standard.Client;
using Bandwidth.Standard.Model;
using Newtonsoft.Json;

//Setting up environment variables
string? BW_ACCOUNT_ID = Environment.GetEnvironmentVariable("BW_ACCOUNT_ID");
string? BW_CLIENT_ID = Environment.GetEnvironmentVariable("BW_CLIENT_ID");
string? BW_CLIENT_SECRET = Environment.GetEnvironmentVariable("BW_CLIENT_SECRET");
string? BW_MESSAGING_APPLICATION_ID = Environment.GetEnvironmentVariable("BW_MESSAGING_APPLICATION_ID");
string? BW_NUMBER = Environment.GetEnvironmentVariable("BW_NUMBER");
string? LOCAL_PORT = Environment.GetEnvironmentVariable("LOCAL_PORT");

if (BW_ACCOUNT_ID == null || BW_CLIENT_ID == null || BW_CLIENT_SECRET == null || BW_MESSAGING_APPLICATION_ID == null
|| BW_NUMBER == null || !int.TryParse(LOCAL_PORT, out int port))
{
Console.WriteLine("Please set the environmental variables defined in the README");
Environment.Exit(1);
return;
}

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls($"http://localhost:{port}");
var app = builder.Build();

Configuration configuration = new Configuration();
configuration.OAuthClientId = BW_CLIENT_ID;
configuration.OAuthClientSecret = BW_CLIENT_SECRET;

var statusMessages = new Dictionary<StatusCallbackTypeEnum, string>
{
[StatusCallbackTypeEnum.Sending] = "message-sending type is only for MMS.",
[StatusCallbackTypeEnum.Delivered] = "Your message has been handed off to the Bandwidth's MMSC network, but has not been confirmed at the downstream carrier.",
[StatusCallbackTypeEnum.Failed] = "For MMS and Group Messages, you will only receive this callback if you have enabled delivery receipts on MMS."
};

var replies = new Dictionary<string, string>
{
["stop"] = "STOP: OK, you'll no longer receive messages from us.",
["quit"] = "QUIT: OK, you'll no longer receive messages from us.",
["help"] = "Valid words are: STOP, QUIT, HELP, and INFO. Reply STOP or QUIT to opt out.",
["info"] = "INFO: This is the test responder service. Reply STOP or QUIT to opt out."
};
const string DEFAULT_REPLY = "Please respond with a valid word. Reply HELP for help.";

async Task<T?> ReadBody<T>(HttpContext context)
{
try
{
using var streamReader = new StreamReader(context.Request.Body);
return JsonConvert.DeserializeObject<T>(await streamReader.ReadToEndAsync());
}
catch (JsonException)
{
return default;
}
}

string AutoReply(string? text)
{
return replies.GetValueOrDefault((text ?? "").Trim().ToLower(), DEFAULT_REPLY);
}

async Task SendReply(string to, string text)
{
MessageRequest messageRequest = new MessageRequest(
applicationId: BW_MESSAGING_APPLICATION_ID,
to: new List<string> { to },
from: BW_NUMBER,
text: text
);

try
{
MessagesApi apiInstance = new MessagesApi(configuration);
Message message = await apiInstance.CreateMessageAsync(BW_ACCOUNT_ID, messageRequest);
Console.WriteLine($"Sent reply {message.Id}\nTo: {to}\nText: {text}");
}
catch (Exception e)
{
Console.WriteLine($"Failed to send reply: {e.Message}");
}
}

app.MapPost("/callbacks/outbound/messaging/status", async (HttpContext context) =>
{
var callbacks = await ReadBody<List<StatusCallback>>(context);
if (callbacks == null || !callbacks.All(callback => statusMessages.ContainsKey(callback.Type)))
{
return Results.BadRequest();
}

foreach (var callback in callbacks)
{
Console.WriteLine(statusMessages[callback.Type]);
}

return Results.NoContent();
});

app.MapPost("/callbacks/inbound/messaging", async (HttpContext context) =>
{
var callbacks = await ReadBody<List<InboundCallback>>(context);
if (callbacks == null || !callbacks.All(callback => callback.Type == InboundCallbackTypeEnum.MessageReceived))
{
return Results.BadRequest();
}

foreach (var callback in callbacks)
{
var message = callback.Message;
Console.WriteLine($"{callback.Description}\nTo: {message.To[0]}\nFrom: {message.From}\nText: {message.Text}");
await SendReply(message.From, AutoReply(message.Text));
}

return Results.NoContent();
});

app.Run();
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
Expand All @@ -21,7 +20,6 @@
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7278;http://localhost:5001",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Bandwidth Samples
Copyright (c) 2026 Bandwidth Samples

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
61 changes: 31 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,54 +1,56 @@
# Send Auto Response C#
# Messaging Auto Respond

<a href="http://dev.bandwidth.com/docs/messaging/quickStart">
<a href="https://dev.bandwidth.com/docs/messaging/quickStart">
<img src="./icon-messaging.svg" title="Messaging Quick Start Guide" alt="Messaging Quick Start Guide"/>
</a>

# Table of Contents
# Table of Contents

- [Send Auto Response C#](#send-auto-response-c)
- [Table of Contents](#table-of-contents)
- [Description](#description)
- [Pre-Requisites](#pre-requisites)
- [Environmental Variables](#environmental-variables)
- [Running the Application](#running-the-application)
- [Callback URLs](#callback-urls)
- [Ngrok](#ngrok)
* [Description](#description)
* [Pre-Requisites](#pre-requisites)
* [Running the Application](#running-the-application)
* [Environmental Variables](#environmental-variables)
* [Callback URLs](#callback-urls)
* [Ngrok](#ngrok)

# Description

This app automatically responds to texts sent to the associated Bandwidth number. Any texts sent to the `BW_NUMBER` will be auto-responded to using the auto response map. Valid words are: `STOP`, `QUIT`, `HELP`, and `INFO`.
This sample app automatically replies to texts sent to your Bandwidth number. The reply depends on the text received: `STOP`, `QUIT`, `HELP` and `INFO` each get their own reply, and anything else gets a prompt to reply `HELP`. Keywords are matched against the whole message and are not case sensitive.

To use this app, you must check the "Use multiple callback URLs" box on the application page in Dashboard. Then in Dashboard, set the INBOUND CALLBACK to `/callbacks/inbound/messaging` and the STATUS CALLBACK to `/callbacks/outbound/messaging/status`. The same can be accomplished via the Dashboard API by setting InboundCallbackUrl and OutboundCallbackUrl respectively.
The `STOP` and `QUIT` replies are for demonstration only. This app doesn't keep track of opt-outs, so it will keep replying to a number that has sent `STOP`.

Inbound callbacks are sent notifying you of a received message on a Bandwidth number, this app sends a custom response to those messages based on their content. Outbound callbacks are status updates for messages sent from a Bandwidth number, this app has a dedicated response for each type of status update.
In order to use the correct endpoints, you must check the "Use multiple callback URLs" box on the application page in Dashboard. Then in Dashboard, set the INBOUND CALLBACK to `/callbacks/inbound/messaging` and the STATUS CALLBACK to `/callbacks/outbound/messaging/status`. The same can be accomplished via the Dashboard API by setting `InboundCallbackUrl` and `OutboundCallbackUrl` respectively.

Inbound callbacks are sent notifying you of a received message on a Bandwidth number. This app prints the phone numbers involved and the text received, then sends the reply. Outbound callbacks are status updates for messages sent from a Bandwidth number, this app has a dedicated response for each type of status update.

# Pre-Requisites

In order to use the Bandwidth API users need to set up the appropriate application at the [Bandwidth Dashboard](https://dashboard.bandwidth.com/) and create API tokens.

To create an application log into the [Bandwidth Dashboard](https://dashboard.bandwidth.com/) and navigate to the `Applications` tab. Fill out the **New Application** form selecting the service that the application will be used for (this sample app uses a messaging application). All Bandwidth services require publicly accessible Callback URLs, for more information on how to set one up see [Callback URLs](#callback-urls).
To create an application log into the [Bandwidth Dashboard](https://dashboard.bandwidth.com/) and navigate to the `Applications` tab. Fill out the **New Application** form selecting the service (Messaging or Voice) that the application will be used for. All Bandwidth services require publicly accessible Callback URLs, for more information on how to set one up see [Callback URLs](#callback-urls).

For more information about API credentials see our [Account Credentials](https://dev.bandwidth.com/docs/account/credentials) page.

# Environmental Variables
# Running the Application

The sample app uses the below environmental variables.
Use the following command to run the application:

```sh
BW_ACCOUNT_ID # Your Bandwidth Account Id
BW_USERNAME # Your Bandwidth API Username
BW_PASSWORD # Your Bandwidth API Password
BW_MESSAGING_APPLICATION_ID # Your Messaging Application Id created in the dashboard
cd AutoRespond/
dotnet run
```

# Running the Application
# Environmental Variables

Use the following command to run the application:
The sample app uses the below environmental variables.

```sh
cd SendAutoRespond/
dotnet run
BW_ACCOUNT_ID # Your Bandwidth Account Id
BW_CLIENT_ID # Your Bandwidth API OAuth Client Id
BW_CLIENT_SECRET # Your Bandwidth API OAuth Client Secret
BW_NUMBER # The Bandwidth phone number involved with this application
BW_MESSAGING_APPLICATION_ID # Your Messaging Application Id created in the dashboard
LOCAL_PORT # The port number you wish to run the sample on
```

# Callback URLs
Expand All @@ -62,11 +64,10 @@ Below are the callback paths:
## Ngrok

A simple way to set up a local callback URL for testing is to use the free tool [ngrok](https://ngrok.com/).
After you have downloaded and installed `ngrok` run the following command to open a public tunnel to your port (in this case port 5001).
After you have downloaded and installed `ngrok` run the following command to open a public tunnel to your port (`$LOCAL_PORT`)

```cmd
ngrok http 5001
```sh
ngrok http $LOCAL_PORT
```
You can view your public URL at `http://127.0.0.1:4040` after ngrok is running. You can also view the status of the tunnel and requests/responses here.

*Note: If you would like to change your port number feel free to do so. However, if you do change the port you will also need to change the number appended to the application URL in the `launchSettings.json` file located in `SendAutoRespond/Properties/`*
You can view your public URL at `http://127.0.0.1:4040` after ngrok is running. You can also view the status of the tunnel and requests/responses here. Once your public ngrok url has been created, use it as the base of the callback URLs in the messaging application created in the [Pre-Requisites](#pre-requisites) section.
Loading
Loading