How to send an email to user with custom action

I unable to send email to user after getting email id from the user response

action.py

class ActionSendEmail(Action): def name(self): return “action_send_email” # add this to the actions in domain.yml file # this is the name of your custom action

def run(self, dispatcher, tracker, domain):
	# trackers gives us the stored email_id slot done by intents
	# change the slot name as per your requirements and get it using the below code.
	email_id = tracker.get_slot('email_id')
	# this message will be sent to the UI.
	return f"Confirmation email is sent to {email_id}"

can any one help me Thank you.

You’ll need to setup an email service or use a mail server of your own. You can see a complete example email send action using MailChimp in our Sara bot here.

thanks for your help.

i have a doubt . conversation : User:- hi bot: Hi I am karthik. How may i help you user:- I want to know about your solutions. bot:- Can you please send me you mail id. user:- karthik@gmail.com

Here users as given mail id after that bot has to send a default email like Welcome to XXX company and product details.

So is it possible in this way. Please guide me.

Yes, you should read about Forms in this forum post and our docs.

Hi, Sorry for delay.

by using the forms action how can i send the default mails to users please guide me more. If you have any sample code please send me

hi MailChimp is not free for every one please tell me

I can’t speak for Mailchimp or the other mail services. I think they have a free tier but I don’t know the details. Rasa doesn’t include an mail server.

Thank you for your information. So is there any way to send a default mail to senders

please guide me

actions.py import logging from datetime import datetime from typing import Text, Dict, Any, List import json

from rasa_sdk import Action, Tracker from rasa_sdk.executor import CollectingDispatcher from rasa_sdk.forms import FormAction from rasa_sdk.events import SlotSet, UserUtteranceReverted, ConversationPaused

import requests class ActionStoreEmail(Action): “”“Stores the email in a slot”""

def name(self):
	return "action_store_email"

def run(self, dispatcher, tracker, domain):
	email = next(tracker.get_latest_entity_values('email'), None)

    # if no email entity was recognised, prompt the user to enter a valid
    # email and go back a turn in the conversation to ensure future
    # predictions aren't affected
	if not email:
		email = tracker.latest_message.get('text')
		dispatcher.utter_message("We need your email, "
                                 "please enter a valid one.")
		return [UserUtteranceReverted()]

	return [SlotSet('email', email)]     

class sendmail(FormAction): def name(self): return “action_sendmail”

@staticmethod
def required_slots(tracker):
    return ["email"]


def slot_mappings(self):
    return {
        "email": [
            self.from_entity(entity="email"),
            self.from_text(intent="enter_data"),
        ]
    }

def validate_email(self, value, dispatcher, tracker, domain):
    """Check to see if an email entity was actually picked up by duckling."""

    if any(tracker.get_latest_entity_values("email")):
        # entity was picked up, validate slot
        return {"email": value}
    else:
        # no entity was picked up, we want to ask again
        dispatcher.utter_template("utter_no_email", tracker)
        return {"email": None}

def submit(
    self,
    dispatcher: CollectingDispatcher,
    tracker: Tracker,
    domain: Dict[Text, Any],
) -> List[Dict]:
    """Once we have an email, attempt to add it to the database"""

    email = tracker.get_slot("email")
    client = MailChimpAPI(config.mailchimp_api_key)
    # if the email is already subscribed, this returns False
    added_to_list = client.subscribe_user(config.mailchimp_list, email)
     
     
    # utter submit template
    if added_to_list:
        dispatcher.utter_template("utter_confirmationemail", tracker)
    else:
        dispatcher.utter_template("utter_already_subscribed", tracker)
        
    
    

def run(self, dispatcher, tracker,domain):
    import requests
    from email.message import EmailMessage
    
    From= tracker.get_slot("From")
    To= tracker.get_slot("email")
    User= tracker.get_slot("name")
    
    msg= EmailMessage()
    msg['Subject']= ("Thank You For Your visit ")
    msg[To]= 'receving_email_address'
    
    msg.set_content("Hi,/n I am Alisa from ")
    response = unirest.post("https://OutlookMailstefan-skliarovV1.p.rapidapi.com/sendMessage",
      headers={
      "X-RapidAPI-Host": "OutlookMailstefan-skliarovV1.p.rapidapi.com",
      "X-RapidAPI-Key": "4f0e828645msh38bfffaf5438379p18ee2bjsn93ce93b0cd4f",
      "Content-Type": "application/x-www-form-urlencoded"

} )

    return []

i have written code like above , but the problem here is now bot prediction was wrong.

So is there any way to send a default mail to senders

I’m not sure I follow your question but I think you’re asking how to send an email with Python. Either way, sending email is not an inherent feature of Rasa, it would be something you would do in a Python action using whatever modules and mail services you choose.

the problem here is now bot prediction was wrong

I think you’re saying that the email entity was not extracted from an intent. Is that correct? If so, please paste your intent examples here.

Thank you for your help

Chatbot is working fine. Issue resolved.

So Rasa did not have a module to send a default mail to a user. In action.py file I have written the mail configuration but it is not working. can you help on this.

My Bot is for marketing so when user ask about company product, it will give brief introduction. So in this process bot will ask user details. So user will give mail id after that bot as to send an email to user about our products after conversation.

action.py

class MailForm(FormAction):

def name(self):
    return "Send_MailtoUser"
    
@staticmethod
def required_slots(tracker : Tracker) -> List[Text]:
    return ["name", "email"]

def slot_mappings(self):
    
    return {"name": [self.from_entity(entity="name"),self.from_text()],
            "email": [self.from_entity(entity="email"), self.from_text(intent="enter_data")]}
            
            


def validate_email(self, value, dispatcher, tracker, domain):
    """Check to see if an email entity was actually picked up by duckling."""

    if any(tracker.get_latest_entity_values("email")):
        # entity was picked up, validate slot
        return {"email": value}
    else:
        # no entity was picked up, we want to ask again
        dispatcher.utter_template("utter_no_email", tracker)
        return {"email": None}
        
def submit(self,
           dispatcher: CollectingDispatcher,
           tracker: Tracker,
           domain: Dict[Text, Any]) -> List[Dict]:
    """Define what the form has to do
        after all required slots are filled"""

    # utter submit template
    dispatcher.utter_template('utter_submit', tracker)
    return []

class DefaultMail(Action): def name(self): return(“action_Default_Mail”)

def run(self, dispatcher, tracker, domain):
    import os
    import email, smtplib, ssl
    from email.mime.base import MIMEBase
    from email.mime.multipart import MIMEMultipart
    from email.mime.text import MIMEText

    
    subject = "Thank you for visiting Lanconic.com"
    
    body = "Hello..  For more details please visit our website"
       
    sender_email = "karthik@lanconic.com"
    receiver_email = tracker.get_slot("email")
    password = xyx
    
    
    # Create a multipart message and set headers
    message = MIMEMultipart()
    message["From"] = sender_email
    message["To"] = receiver_email
    message["Subject"] = subject
    
    # Add body to email
    message.attach(MIMEText(body, "plain"))
    
    filename = "apigateway-dg.pdf"  # In same directory as script
    
    # Open PDF file in binary mode
    with open(filename, "rb") as attachment:
        # Add file as application/octet-stream
        # Email client can usually download this automatically as attachment
        part = MIMEBase("application", "octet-stream")
        part.set_payload(attachment.read())
    
        # Encode file in ASCII characters to send by email    
        encoders.encode_base64(part)
    
    
        # Add header as key/value pair to attachment part
        part.add_header(
        "Content-Disposition",
        f"attachment; filename= {filename}",
        )
    
        # Add attachment to message and convert message to string
        message.attach(part)
        text = message.as_string()
    
        # Log in to server using secure context and send email
        context = ssl.create_default_context()
        s = smtplib.SMTP(host='smtp.office365.com', port=587)
        s.starttls()
        s.login(sender_email, password)
        s.sendmail(sender_email, receiver_email, message.as_string())
        
        return[]

this code working when we run as rasa run actions but when we use with model not working the custom action.

We have a complete working example that collects a users email address and sends them an email in our rasa-demo.

You should review the intent, stories and code related to the email intent. You can clone this to your system. Replace mailchimp with the mailing service of your choice.

Review the logs to determine if your actions are being called as you expect them to.

2 Likes

actions.py class MailForm(FormAction):

def name(self):
    return "Send_MailtoUser"
    
@staticmethod
def required_slots(tracker : Tracker) -> List[Text]:
    return ["email"]

def slot_mappings(self):
    return {
        "email": [
            self.from_entity(entity="email"),
            self.from_text(intent="enter_data"),
        ]
    }          
            


def validate_email(self, value, dispatcher, tracker, domain):
    """Check to see if an email entity was actually picked up by duckling."""

    if any(tracker.get_latest_entity_values("email")):
        # entity was picked up, validate slot
        return {"email": value}
    else:
        # no entity was picked up, we want to ask again
        dispatcher.utter_template("utter_no_email", tracker)
        return {"email": None}
        
def submit(self,
    dispatcher: CollectingDispatcher,
    tracker: Tracker,
    domain: Dict[Text, Any]) -> List[Dict]:
           
      
    email = tracker.get_slot("email")
           
           # utter submit template
    dispatcher.utter_template('utter_submit', tracker)
           
 
def run(self, dispatcher, tracker, domain):
    email = next(tracker.get_latest_entity_values('email'), None)  
    email = tracker.get_slot("email")
    os.chdir("C:\\Users\\karthik\\Desktop")

    subject = "Thank you for visiting Lanconic.com"
  
    body = "Hello.. \n\n Greetings from Lanconic.!! \n\n Thank You for your enquiry.\n\n Based on our Conversation I have found the following Content which would help you further. \n 1. Smart Recruit. \n 2. Employee Time Sheet Management. \n 3. CareerFetch. \n 4. Our Award Winning - Workforce Capital Management Solution. \n\n Hope to See you again.\n\n Bye.\n \n Best Regards \n Alisa. \n \n For more details please visit our website – www.lanconic.com"
       
    sender_email = 
    email = [tracker.get_slot("email")]
    password = "
    
    
     # Create a multipart message and set headers
    message = MIMEMultipart()
    message["From"] = sender_email
    message["To"] = email
    message["Subject"] = subject
    
             # Add body to email
    message.attach(MIMEText(body, "plain"))
    
    filename = "apigateway-dg.pdf"  # In same directory as script
    
            # Open PDF file in binary mode
    with open(filename, "rb") as attachment:
     # Add file as application/octet-stream
     # Email client can usually download this automatically as attachment
        part = MIMEBase("application", "octet-stream")
        part.set_payload(attachment.read())
    
            # Encode file in ASCII characters to send by email    
    encoders.encode_base64(part)        
    
            # Add header as key/value pair to attachment part
    part.add_header(
        "Content-Disposition",
        f"attachment; filename= {filename}",
    )
    
         # Add attachment to message and convert message to string
    message.attach(part)
    text = message.as_string()
    
            # Log in to server using secure context and send email
    context = ssl.create_default_context()
    s = smtplib.SMTP(host='smtp.office365.com', port=587)
    s.starttls()
    s.login(sender_email, password)
    s.sendmail(sender_email, email, message.as_string())
    return[]    

after user entering the email i am getting error

2019-12-17 00:54:50 ERROR rasa.core.processor - Encountered an exception while running action ‘Send_MailtoUser’. Bot will continue, but the actions events are lost. Please check the logs of your action server for more information. 2019-12-17 00:54:50 DEBUG rasa.core.processor - Failed to execute custom action. Traceback (most recent call last): File “c:\users\karthik\appdata\local\continuum\anaconda3\envs\rasabot\lib\site-packages\rasa\core\actions\action.py”, line 451, in run json=json_body, method=“post”, timeout=DEFAULT_REQUEST_TIMEOUT File “c:\users\karthik\appdata\local\continuum\anaconda3\envs\rasabot\lib\site-packages\rasa\utils\endpoints.py”, line 148, in request resp.status, resp.reason, await resp.content.read() rasa.utils.endpoints.ClientResponseError: 500, Internal Server Error, body=‘b’\n

please help me regarding this issue

sorry for late issue got resolve

how the issue resolved actually i m also facing the same issue i have build a restaurant search chatbot which asks users email address for send restraunt details its working fine on local server but after deploying on slack mail is not getting sent and even email is not recognizing as an entity

hi May i know your deployment process

I have similar doubt can youhelp me

hi iam new for rasa can anyone please tell me how to communicate to mail

Sending email through action

Can anyone provide sample chatbot code to send user inputted data through email