Skip to main content
Glama

generate_template

Create responsive email templates for newsletters, welcome messages, promotional campaigns, and transactional emails using MJML markup with customizable colors, fonts, and variables.

Instructions

Generate pre-built email templates

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
templateYesTemplate type
variablesNoTemplate variables to replace
customColorsNoCustom color scheme
customFontsNoCustom fonts
outputPathNoSave template to file path

Implementation Reference

  • Main handler function that parses input using GenerateTemplateSchema, generates MJML template via getTemplate helper, optionally saves to outputPath, and returns structured response with the MJML content.
    async handleGenerateTemplate(args) {
      const parsed = GenerateTemplateSchema.parse(args);
      log.info(`Generating template: ${parsed.template}`);
    
      const template = this.getTemplate(parsed.template, parsed.variables, parsed.customColors, parsed.customFonts);
      
      const saveResult = await this.saveOutput(template, parsed.outputPath);
    
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify({
              success: true,
              template: parsed.template,
              mjml: template,
              saved: saveResult,
            }, null, 2),
          },
        ],
      };
    }
  • Zod schema defining input parameters for the generate_template tool: required template type (enum), optional variables, custom colors/fonts, and output path.
    const GenerateTemplateSchema = z.object({
      template: z.enum([
        'newsletter', 'welcome', 'promotional', 'transactional', 
        'password-reset', 'verification', 'announcement', 'invitation'
      ]).describe('Template type'),
      variables: z.record(z.string()).optional().describe('Template variables to replace'),
      customColors: z.record(z.string()).optional().describe('Custom color scheme'),
      customFonts: z.record(z.string()).optional().describe('Custom fonts'),
      outputPath: z.string().optional().describe('Save template to file path'),
    });
  • index.js:211-240 (registration)
    Tool registration in ListToolsRequestHandler, providing name, description, and inputSchema mirroring the Zod schema for MCP tool discovery.
      name: 'generate_template',
      description: 'Generate pre-built email templates',
      inputSchema: {
        type: 'object',
        properties: {
          template: {
            type: 'string',
            enum: ['newsletter', 'welcome', 'promotional', 'transactional', 'password-reset', 'verification', 'announcement', 'invitation'],
            description: 'Template type',
          },
          variables: {
            type: 'object',
            description: 'Template variables to replace',
          },
          customColors: {
            type: 'object',
            description: 'Custom color scheme',
          },
          customFonts: {
            type: 'object',
            description: 'Custom fonts',
          },
          outputPath: {
            type: 'string',
            description: 'Save template to file path',
          },
        },
        required: ['template'],
      },
    },
  • Helper method that selects predefined MJML email templates based on type, applies custom colors/fonts/default variables via replacement, and returns the final MJML string.
      getTemplate(type, variables = {}, customColors = {}, customFonts = {}) {
        const defaultColors = {
          primary: '#007bff',
          secondary: '#6c757d',
          success: '#28a745',
          danger: '#dc3545',
          warning: '#ffc107',
          info: '#17a2b8',
          light: '#f8f9fa',
          dark: '#343a40',
        };
    
        const colors = { ...defaultColors, ...customColors };
    
        const defaultFonts = {
          'Lato': 'https://fonts.googleapis.com/css?family=Lato:300,400,700,900',
          'Open Sans': 'https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800',
        };
    
        const fonts = { ...defaultFonts, ...customFonts };
    
        const defaultVars = {
          company_name: 'Your Company',
          company_logo: 'https://via.placeholder.com/150x50',
          unsubscribe_url: '#',
          website_url: '#',
          support_email: 'support@example.com',
          current_year: new Date().getFullYear(),
          ...variables,
        };
    
        const templates = {
          newsletter: `<mjml>
      <mj-head>
        <mj-attributes>
          <mj-all font-family="Lato, sans-serif" />
          <mj-section background-color="#ffffff" />
          <mj-column padding="0" />
          <mj-text font-size="14px" line-height="22px" color="#4a5568" />
          <mj-button background-color="${colors.primary}" color="#ffffff" border-radius="4px" />
        </mj-attributes>
        <mj-font name="Lato" href="${fonts['Lato']}" />
        <mj-title>{{company_name}} Newsletter</mj-title>
        <mj-preview>Our latest updates and news</mj-preview>
      </mj-head>
      <mj-body background-color="#f7fafc">
        <mj-section background-color="${colors.primary}" padding="40px 0">
          <mj-column>
            <mj-text align="center" color="#ffffff" font-size="24px" font-weight="bold">
              {{company_name}} Newsletter
            </mj-text>
            <mj-text align="center" color="#ffffff" font-size="16px" padding-top="10px">
              {{newsletter_date}}
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section padding="40px 30px">
          <mj-column>
            <mj-text font-size="28px" font-weight="bold" color="#2d3748" align="center">
              {{main_title}}
            </mj-text>
            <mj-text align="center" padding-top="10px">
              {{main_subtitle}}
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section padding="0 30px 40px">
          <mj-column>
            <mj-image src="{{featured_image}}" width="100%" border-radius="8px" />
            <mj-text padding-top="20px" font-size="18px" font-weight="600">
              {{featured_title}}
            </mj-text>
            <mj-text padding-top="10px">
              {{featured_content}}
            </mj-text>
            <mj-button href="{{featured_link}}" padding-top="20px">
              Read More
            </mj-button>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#edf2f7" padding="40px 30px">
          <mj-column>
            <mj-text font-size="20px" font-weight="bold" color="#2d3748" align="center">
              More Updates
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#edf2f7" padding="0 30px 40px">
          <mj-column>
            <mj-text font-size="16px" font-weight="600">
              {{update1_title}}
            </mj-text>
            <mj-text padding-top="5px" font-size="14px">
              {{update1_content}}
            </mj-text>
            <mj-divider border-color="#cbd5e0" border-width="1px" padding="20px 0" />
            <mj-text font-size="16px" font-weight="600">
              {{update2_title}}
            </mj-text>
            <mj-text padding-top="5px" font-size="14px">
              {{update2_content}}
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="${colors.dark}" padding="40px 30px">
          <mj-column>
            <mj-social-element-mode>
              <mj-social facebook-url="{{facebook_url}}" twitter-url="{{twitter_url}}" instagram-url="{{instagram_url}}" />
            </mj-social-element-mode>
            <mj-text align="center" color="#ffffff" font-size="12px" padding-top="20px">
              © {{current_year}} {{company_name}}. All rights reserved.
            </mj-text>
            <mj-text align="center" color="#ffffff" font-size="12px" padding-top="10px">
              <a href="{{unsubscribe_url}}" style="color: #ffffff; text-decoration: underline;">Unsubscribe</a>
            </mj-text>
          </mj-column>
        </mj-section>
      </mj-body>
    </mjml>`,
    
          welcome: `<mjml>
      <mj-head>
        <mj-attributes>
          <mj-all font-family="Open Sans, sans-serif" />
          <mj-section background-color="#ffffff" />
          <mj-column padding="0" />
          <mj-text font-size="14px" line-height="22px" color="#4a5568" />
          <mj-button background-color="${colors.success}" color="#ffffff" border-radius="6px" font-weight="600" />
        </mj-attributes>
        <mj-font name="Open Sans" href="${fonts['Open Sans']}" />
        <mj-title>Welcome to {{company_name}}!</mj-title>
      </mj-head>
      <mj-body background-color="#f7fafc">
        <mj-section background-color="${colors.success}" padding="60px 0">
          <mj-column>
            <mj-text align="center" color="#ffffff" font-size="36px" font-weight="bold">
              Welcome!
            </mj-text>
            <mj-text align="center" color="#ffffff" font-size="18px" padding-top="10px">
              We're excited to have you on board
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section padding="50px 30px">
          <mj-column>
            <mj-text align="center" font-size="24px" font-weight="600" color="#2d3748">
              Hi {{user_name}},
            </mj-text>
            <mj-text align="center" padding-top="20px" font-size="16px">
              Thank you for joining {{company_name}}! We're thrilled to have you as part of our community.
            </mj-text>
            <mj-text align="center" padding-top="15px" font-size="16px">
              Your account has been successfully created and you're ready to start exploring all the amazing features we have to offer.
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#f7fafc" padding="40px 30px">
          <mj-column>
            <mj-text align="center" font-size="20px" font-weight="600" color="#2d3748">
              Next Steps
            </mj-text>
            <mj-text align="center" padding-top="20px">
              Here are a few things you can do to get started:
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section padding="0 30px 40px">
          <mj-column width="50%">
            <mj-text align="center" font-size="16px" font-weight="600" padding-bottom="10px">
              ✓ Complete Your Profile
            </mj-text>
            <mj-text align="center" font-size="14px">
              Add your personal information and preferences
            </mj-text>
          </mj-column>
          <mj-column width="50%">
            <mj-text align="center" font-size="16px" font-weight="600" padding-bottom="10px">
              ✓ Explore Features
            </mj-text>
            <mj-text align="center" font-size="14px">
              Discover everything {{company_name}} can do
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section padding="0 30px 40px">
          <mj-column>
            <mj-button href="{{dashboard_url}}" font-size="16px" padding="15px 30px">
              Go to Dashboard
            </mj-button>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#edf2f7" padding="30px">
          <mj-column>
            <mj-text align="center" font-size="14px" color="#718096">
              If you have any questions, don't hesitate to contact our support team at
              <a href="mailto:{{support_email}}" style="color: ${colors.primary};">{{support_email}}</a>
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="${colors.dark}" padding="30px">
          <mj-column>
            <mj-text align="center" color="#ffffff" font-size="12px">
              © {{current_year}} {{company_name}}. All rights reserved.
            </mj-text>
          </mj-column>
        </mj-section>
      </mj-body>
    </mjml>`,
    
          promotional: `<mjml>
      <mj-head>
        <mj-attributes>
          <mj-all font-family="Lato, sans-serif" />
          <mj-section background-color="#ffffff" />
          <mj-column padding="0" />
          <mj-text font-size="14px" line-height="22px" color="#4a5568" />
          <mj-button background-color="${colors.danger}" color="#ffffff" border-radius="4px" font-weight="bold" />
        </mj-attributes>
        <mj-font name="Lato" href="${fonts['Lato']}" />
        <mj-title>🔥 Limited Time Offer from {{company_name}}</mj-title>
        <mj-preview>Don't miss out on these amazing deals!</mj-preview>
      </mj-head>
      <mj-body background-color="#000000">
        <mj-section background-color="${colors.danger}" padding="20px 0">
          <mj-column>
            <mj-text align="center" color="#ffffff" font-size="24px" font-weight="bold">
              🔥 FLASH SALE
            </mj-text>
            <mj-text align="center" color="#ffffff" font-size="18px" padding-top="5px">
              {{discount_percentage}} OFF EVERYTHING
            </mj-text>
            <mj-text align="center" color="#ffffff" font-size="16px" padding-top="5px">
              Ends in {{time_remaining}}
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#ffffff" padding="40px 30px">
          <mj-column>
            <mj-text align="center" font-size="28px" font-weight="bold" color="#2d3748">
              {{promotion_title}}
            </mj-text>
            <mj-text align="center" padding-top="15px" font-size="16px">
              {{promotion_description}}
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#fff3cd" padding="20px 30px">
          <mj-column>
            <mj-text align="center" font-size="18px" font-weight="600" color="#856404">
              ⏰ Hurry! Limited Time Offer
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section padding="30px">
          <mj-column>
            <mj-image src="{{product_image}}" width="100%" />
            <mj-text align="center" font-size="20px" font-weight="bold" padding-top="20px">
              {{product_name}}
            </mj-text>
            <mj-text align="center" padding-top="10px">
              {{product_description}}
            </mj-text>
            <mj-text align="center" padding-top="10px">
              <span style="text-decoration: line-through; color: #718096;">${{original_price}}</span>
              <span style="font-size: 24px; font-weight: bold; color: ${colors.danger};">${{sale_price}}</span>
            </mj-text>
            <mj-button href="{{shop_url}}" background-color="${colors.danger}" padding-top="20px">
              Shop Now - {{discount_percentage}} OFF
            </mj-button>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#f8f9fa" padding="40px 30px">
          <mj-column>
            <mj-text align="center" font-size="18px" font-weight="600" color="#2d3748">
              Why Choose {{company_name}}?
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#f8f9fa" padding="0 30px 40px">
          <mj-column width="33%">
            <mj-text align="center" font-size="16px" font-weight="600">
              ✓ Free Shipping
            </mj-text>
          </mj-column>
          <mj-column width="33%">
            <mj-text align="center" font-size="16px" font-weight="600">
              ✓ 30-Day Returns
            </mj-text>
          </mj-column>
          <mj-column width="34%">
            <mj-text align="center" font-size="16px" font-weight="600">
              ✓ 24/7 Support
            </mj-text>
          </mj-column>
        </mj-section>
    
        <mj-section background-color="#343a40" padding="30px">
          <mj-column>
            <mj-text align="center" color="#ffffff" font-size="12px">
              © {{current_year}} {{company_name}}. All rights reserved.
            </mj-text>
            <mj-text align="center" color="#ffffff" font-size="12px" padding-top="10px">
              <a href="{{unsubscribe_url}}" style="color: #ffffff; text-decoration: underline;">Unsubscribe</a>
            </mj-text>
          </mj-column>
        </mj-section>
      </mj-body>
    </mjml>`,
        };
    
        let template = templates[type] || templates.newsletter;
        
        // Replace variables
        Object.entries(defaultVars).forEach(([key, value]) => {
          const regex = new RegExp(`{{${key}}}`, 'g');
          template = template.replace(regex, value);
        });
    
        return template;
      }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states 'generate' but doesn't clarify if this creates new files, requires specific permissions, has rate limits, or what the output looks like (e.g., HTML code, file saved). This is inadequate for a tool with multiple parameters and potential side effects.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence with zero waste. It's front-loaded and appropriately sized for the tool's complexity, making it easy for an agent to parse quickly without unnecessary details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has 5 parameters, no annotations, and no output schema, the description is incomplete. It doesn't address behavioral aspects like what happens when 'outputPath' is omitted or how 'customColors' and 'customFonts' are applied, leaving significant gaps for the agent to handle.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters well. The description adds no additional meaning beyond the schema, such as explaining how 'variables' map to template placeholders or what 'outputPath' defaults to. Baseline 3 is appropriate as the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'generate' and the resource 'pre-built email templates', making the purpose immediately understandable. However, it doesn't differentiate from sibling tools like 'compile_mjml' or 'validate_mjml', which might also involve template processing, so it misses the highest score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'compile_mjml' or 'validate_mjml'. It lacks context about prerequisites, such as whether it's for creating new templates from scratch or modifying existing ones, leaving the agent to infer usage scenarios.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/shaunie2fly/mjml_mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server