Using the Claude API to Generate Automated Email Responses in C#

A practical guide to integrating Claude’s Messages API into a .NET application for intelligent email reply generation.

Introduction

In this post, I’ll walk through how I built an automated email reply system using the Claude API from Anthropic. The application reads incoming emails, sends them to Claude for analysis, and generates professional reply drafts. This approach can be adapted for customer support, lead response, or any scenario where you need intelligent, context-aware email replies.

Prerequisites

  • .NET 8.0 or later
  • An Anthropic API key (get one at console.anthropic.com)
  • The Anthropic NuGet package

Step 1: Set Up the Project

Create a new .NET console application and install the Anthropic SDK:

dotnet new console -n EmailReplyAgent

cd EmailReplyAgent

dotnet add package Anthropic

Store your API key in appsettings.json:

{

“AnthropicApiKey”: “YOUR_API_KEY_HERE”,

“ClaudeModel”: “claude-sonnet-4-6-20250514”

}

 
Note: Never commit API keys to source control. Use environment variables or a secrets manager in production.
 

Step 2: Fetch Available Timeslots

The Anthropic NuGet package provides a strongly-typed client. Initialization is straightforward:

using Anthropic;

using Anthropic.Models.Messages;

 

var claude = new AnthropicClient

{

ApiKey = config[“AnthropicApiKey”]

};

Step 3: Build the System Prompt

The system prompt is the key to getting high-quality, consistent replies. It defines Claude’s role, the rules it should follow, and the output format you expect. Here’s a simplified example:

string systemPrompt = “””

You are an email reply assistant. You analyze incoming emails

and compose appropriate professional replies.

 

Rules:

– Keep replies professional, warm, and concise

– Start with a greeting using the sender’s first name

– End with a professional closing

– If the email is spam or irrelevant, return ACTION: SKIP

 

Respond in this exact format:

ACTION: REPLY | SKIP

REPLY: <the reply body text>

“””;

Why a structured output format? By asking Claude to respond in a specific format (ACTION + REPLY), we can programmatically parse the response and take different actions. This is much more reliable than trying to interpret free-form text.
 

Step 4: Send the Email to Claude for Analysis

For each incoming email, we construct a user prompt containing the email details and send it to the Messages API:

string userPrompt = $”””

Analyze this email and compose a reply.

 

Subject: {email.Subject}

From: {email.From}

 

Body:

{email.Body}

“””;

 

var response = await claude.Messages.Create(new MessageCreateParams

{

Model = “claude-sonnet-4-6-20250514”,

MaxTokens = 1024,

System = systemPrompt,

Messages = [new() { Role = Role.User, Content = userPrompt }]

});

Key parameters:
  • Model — Choose the model that fits your needs. claude-sonnet-4-6-20250514 offers a good balance of quality and speed for email tasks.
  • MaxTokens — Caps the response length. 1024 tokens is typically enough for a professional email reply.
  • System — The system prompt sets Claude’s behavior and output format.
  • Messages — The conversation history. For a single email analysis, one user message is sufficient.

 

Step 5: Extract the Reply Text

The API response contains content blocks. Extract the text from the first text block:

string claudeReply = “”;

foreach (var block in response.Content)

{

if (block.TryPickText(out var textBlock))

{

claudeReply = textBlock.Text;

break;

}

}

Step 6: Parse the Structured Response

Since we asked Claude to respond in a specific format, we can parse the action and reply body:

static (string Action, string ReplyBody) ParseResponse(string claudeReply)

{

string action = “REPLY”;

string replyBody = “”;

 

var lines = claudeReply.Split(‘\n’);

for (int i = 0; i < lines.Length; i++)

{

string line = lines[i].Trim();

 

if (line.StartsWith(“ACTION:”))

action = line[“ACTION:”.Length..].Trim().ToUpperInvariant();

else if (line.StartsWith(“REPLY:”))

{

replyBody = line[“REPLY:”.Length..].Trim();

// Capture remaining lines as part of the reply

var remaining = lines.Skip(i + 1)

.Where(l => !l.Trim().StartsWith(“ACTION:”));

string rest = string.Join(“\n”, remaining).Trim();

if (!string.IsNullOrEmpty(rest))

replyBody += “\n” + rest;

break;

}

}

 

return (action, replyBody);

}

Step 7: Track Token Usage

The API response includes token counts, which is important for monitoring costs:

Console.WriteLine($”Tokens used – input: {response.Usage.InputTokens}, ” +

$”output: {response.Usage.OutputTokens}”);

At the time of writing, Claude Sonnet costs roughly $3 per million input tokens and $15 per million output tokens. A typical email analysis uses

~500 input tokens and ~300 output tokens, making each reply cost less than a penny.

Putting It All Together

Here’s the complete flow in a single method:

public async Task<string?> GenerateEmailReply(

AnthropicClient claude,

string subject,

string from,

string body)

{

string systemPrompt = “””

You are an email reply assistant. Analyze the incoming email

and compose a professional reply.

 

Rules:

– Keep replies professional, warm, and concise

– Start with a greeting using the sender’s first name

– End with a professional closing

– If the email is spam or irrelevant, return ACTION: SKIP

 

Respond in this format:

ACTION: REPLY | SKIP

REPLY: <the reply body text>

“””;

 

string userPrompt = $”””

Subject: {subject}

From: {from}

 

Body:

{body}

“””;

 

try

{

var response = await claude.Messages.Create(new MessageCreateParams

{

Model = “claude-sonnet-4-6-20250514”,

MaxTokens = 1024,

System = systemPrompt,

Messages = [new() { Role = Role.User, Content = userPrompt }]

});

 

string claudeReply = “”;

foreach (var block in response.Content)

{

if (block.TryPickText(out var textBlock))

{

claudeReply = textBlock.Text;

break;

}

}

 

var (action, replyBody) = ParseResponse(claudeReply);

 

if (action == “SKIP” || string.IsNullOrWhiteSpace(replyBody))

return null; // Not worth replying to

 

return replyBody;

}

catch (Exception ex)

{

Console.WriteLine($”Claude API error: {ex.Message}”);

return null;

}

}

Tips and Best Practices

1. Use Structured Output Formats
Asking Claude to respond with labeled fields (ACTION, REPLY, etc.) makes parsing reliable. You can extend this with additional fields like CATEGORY, PRIORITY, or SENTIMENT.

2. Handle Errors Gracefully
The API can return errors for rate limiting, token limits, or network issues. Always wrap API calls in try/catch and have a fallback strategy.

3. Keep System Prompts Specific
The more specific your system prompt, the better the results. Include examples of good replies, edge cases to handle, and explicit instructions for what to skip.

4. Monitor Token Usage
Long email threads can consume significant tokens. Consider truncating email bodies or only sending the most recent messages in a thread.

5. Add a Human Review Step
For production use, consider routing generated replies through an approval workflow before sending. This catches edge cases where Claude’s reply might not be appropriate.

Conclusion

The Claude API makes it straightforward to build intelligent email response systems. With the Anthropic .NET SDK, you can go from incoming email to professional draft reply in just a few lines of code.

The key ingredients are a well-crafted system prompt, structured output parsing, and proper error handling.

The full source code for this example is available as a .NET 8.0 console application using the Anthropic NuGet package (v12.9.0).