para crear un evento en calendario con c# y el estándar ics debemos conocer algunos conceptos básicos de este estándar popular, gracias a Apple y sus calendarios.

Usando Icalendar o ics para los amigos

En Icalendar (de ahora en adelante ics) es un estándar que se hizo muy popular gracias a apple y ios, este estándar se hizo tan popular que empresas como google, Microsoft entre otros adoptaron y se usa en el día a día.

iCalendar permite a los usuarios invitar a reuniones o asignar tareas a otros usuarios a través del correo electrónico. El destinatario del mensaje en formato iCalendar (de tener un programa que lo permita) puede responder fácilmente aceptando la invitación, o proponiendo otra fecha y hora para la misma.

wikipedia en español

como todo en este mundo de la informática, va evolucionando y cada vez podemos hacer mas compleja estas invitaciones, podemos hacer algo muy simple (que es lo que vamos a ver en este post) hasta algo muy complicado como el siguiente ejemplo 

y hay invitaciones mas complejas, como colocar mapas, lapsos de tiempo etc

nosotros vamos a usar el siguiente ejemplo y vamos a programarlo, la ventaja de usar ics es que es un formato muy simple, tan simple que podemos usar un editor de texto y hacerlo manualmente, pero nos gusta hacer la vida más fácil.

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:uid1@example.com
DTSTAMP:19970714T170000Z
ORGANIZER;CN=John Doe:MAILTO:john.doe@example.com
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
GEO:48.85299;2.36885
END:VEVENT
END:VCALENDAR

lo que vemos en la parte de arriba es lo básico que nos piden para crear un evento en el calendario.

Creando un evento en calendario

Principalmente vamos a usar las siguientes :

  • DateTime  – Formato de tiempo
  • TimeZoneInfo – Conversión e información de la hora y fecha
  • Directory – crear elementos en el disco duro
  • IO/ StreamWrite – escribir un archivo 
  • SmtpClient – configuración del cliente para enviar correo electrónico
  • MailAddress – formatos para correo electrónico
  • MailMessege – envió del contenido y agregar multimedia
  • NetworkCredential – configuración para enviar todo el correo electrónico

Clase principal para crear un evento en calendario

en nuestra clase principal (Program.cs) vamos a dividirlo de la siguientes clases:

  • Pedir los elementos a llenar
  • Creación y transformación de las fechas
  • creación del documento
  • llamado a enviar email
            Console.Write("Introduce email del invitado");
            string emailid = Console.ReadLine();
            Console.Write("Nombre del invitado");
            string nameinv = Console.ReadLine();
            Console.Write("\nNombre de organizador");
            string nombreorg = Console.ReadLine();
            Console.Write("\nEmail de organizador");
            string tuEmail = Console.ReadLine();


            Console.Write("\nAño inicio");
            int anoin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nmes inicio");
            int mesin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nDia inicio");
            int diain = Convert.ToInt16(Console.ReadLine());

            Console.Write("\nHora inicio 0-23");
            int horain = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nMinutos inicio 0-59");
            int minin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nSegundos inicio 0-59");
            int segin = Convert.ToInt16(Console.ReadLine());
            
            Console.Write("\nAño fin");
            int anofin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nmes fin");
            int mesfin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nDia fin");
            int diafin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nHora fin 0-23");
            int horafin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nMin fin 0-59");
            int minfin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nSegundo fin 0-59");
            int segfin = Convert.ToInt16(Console.ReadLine());

            Console.Write("\nAsunto no max-60");
            string asunto = Console.ReadLine();

En el código anterior pedimos los valores requerido por consola, en la parte de las horas pedimos números específicos:

Horas pedimos de 0 a 23, que corresponde a la hora en formato 24h, recordemos que 24 horas no existe si no que es 0 horas.

En los minutos y segundos pedimos de 0 a 59.

si ustedes quieren mejorar más esto, pueden hacer validaciones que realmente se ingrese lo que se pide y no introduzcan texto o algún carácter no deseado.

siguiendo el código anterior llamamos a nuestra clase creadora:

CrearICS cr = new CrearICS();
            cr.CreameEsta(emailid, nameinv, nombreorg, tuEmail, asunto, anoin, mesin, diain, horain, minin, segin, anofin, mesfin, diafin, horafin, minfin, segfin);
            Console.Write("------------------- \n");
            Console.Write("se creo archivo");
            Console.Write("\n------------------- \n");
            Console.ReadKey();

Clase que convierte las fechas

para crear las fechas validas para el ics necesitamos convertirlas a utc, y en un formato de añomesdiahorasminutossegundosZ.

por esta razón creamos la clase que lo podemos reutilizar varias veces .

algunas clases tienen un poco de humor y son de doble sentido, esto es para hacer mas divertido el código, pueden dejar en los comentarios si no les agrada esto.

class Fechas
    {
        public String Regresameesta(int ano, int mes, int dia, int hora = 0, int minutos = 0, int segundo = 0)
        {
//construimos la fecha actual
            DateTime dt2 = new DateTime(ano, mes, dia, hora, minutos, segundo);
            TimeZoneInfo localZone = TimeZoneInfo.Local;
            DateTime dateTime;
//convertimos a utc
            dateTime = TimeZoneInfo.ConvertTimeToUtc(dt2, TimeZoneInfo.Local);
            //regresar
            //transformamos al formato que nos pide ics
            return dateTime.ToString("yyyyMMddTHHmmssZ");
        }
        public String Ahorawey()
        {
//esta funcion no se usa pero es en caso que elijamos la hora actual
            DateTime dth = DateTime.Now;
            DateTime dTime;
            dTime = TimeZoneInfo.ConvertTimeToUtc(dth, TimeZoneInfo.Local);
            return dTime.ToString("yyyyMMddTHHmmssZ");
        }
    }

En la primera función lo que hacemos es pasar los datos necesarios para crear el formato fecha y transformarlo a utc.

Creación del fiche ics

En esta clase lo que hacemos es lo siguiente, creamos un lugar donde se guardara la ruta de los documentos creados.

string lugar = "./evento/";
System.IO.Directory.CreateDirectory(lugar);

creamos el nombre del documento y asignamos en donde se guarda y comenzamos a escribir

string nombre = "prueba" + DateTime.Now.ToString("ddMMyyyyss") + ".ics";
 lugar = System.IO.Path.Combine(lugar, nombre);
 using (System.IO.StreamWriter mylogs = System.IO.File.AppendText(lugar))
            {

creamos un string que guarde todos los espacios y enter (texto libre) para esto debemos agregar un @ antes del string, como dato curioso, debemos respetar los espacios de la plantilla anterior, si pegamos algún dato o tiene un enter de mas, puede salir con error.

                String ics = @"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:"+ email +
                            "\nDTSTAMP:" + f.Ahorawey() +
                            "\nORGANIZER; CN="+nombreev+":MAILTO:"+emailor +
                            "\nDTSTART:" + f.Regresameesta(ast, mast, dast, hast, mnast, sast) +
                            "\nDTEND:" + f.Regresameesta(aed, med, ded, hed, mned, sed) +

                            "\nSUMMARY:" + asunto+
                            "\nGEO:" + "25.6534664;-100.3407974"+
                            "\nEND:VEVENT" +
                            "\nEND:VCALENDAR";
                mylogs.WriteLine(ics);
                mylogs.Close();
            }

no se preocupen si no se ve bien (desgraciadamente wordpress actualizo su editor y no puedo usar mi plugin de código) al final de este post dejare el link del repositorio.

por ultimo creado el archivo ics, vamos a enviarlo por correo electrónico al que queremos invitar.

Console.Write("\n------------------- \n");
            email mail = new email(email, nombreinv, emailor, nombre, nombreev);
            Console.Write("correo enviado");

Este es el código completo de la clase principal


    class Program
    {
        static void Main(string[] args)
        {
            Fechas f = new Fechas();
            Console.Write("Introduce email del invitado");
            string emailid = Console.ReadLine();
            Console.Write("Nombre del invitado");
            string nameinv = Console.ReadLine();
            Console.Write("\nNombre de organizador");
            string nombreorg = Console.ReadLine();
            Console.Write("\nEmail de organizador");
            string tuEmail = Console.ReadLine();


            Console.Write("\nAño inicio");
            int anoin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nmes inicio");
            int mesin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nDia inicio");
            int diain = Convert.ToInt16(Console.ReadLine());

            Console.Write("\nHora inicio 0-23");
            int horain = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nMinutos inicio 0-59");
            int minin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nSegundos inicio 0-59");
            int segin = Convert.ToInt16(Console.ReadLine());
            
            Console.Write("\nAño fin");
            int anofin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nmes fin");
            int mesfin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nDia fin");
            int diafin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nHora fin 0-23");
            int horafin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nMin fin 0-59");
            int minfin = Convert.ToInt16(Console.ReadLine());
            Console.Write("\nSegundo fin 0-59");
            int segfin = Convert.ToInt16(Console.ReadLine());

            Console.Write("\nAsunto no max-60");
            string asunto = Console.ReadLine();
            
            CrearICS cr = new CrearICS();
            cr.CreameEsta(emailid, nameinv, nombreorg, tuEmail, asunto, anoin, mesin, diain, horain, minin, segin, anofin, mesfin, diafin, horafin, minfin, segfin);
            Console.Write("------------------- \n");
            Console.Write("se creo archivo");
            Console.Write("\n------------------- \n");
            Console.ReadKey();
        }
        
    }
    class Fechas
    {
        public String Regresameesta(int ano, int mes, int dia, int hora = 0, int minutos = 0, int segundo = 0)
        {
            DateTime dt2 = new DateTime(ano, mes, dia, hora, minutos, segundo);
            TimeZoneInfo localZone = TimeZoneInfo.Local;
            DateTime dateTime;
            dateTime = TimeZoneInfo.ConvertTimeToUtc(dt2, TimeZoneInfo.Local);
            //regresar
            // dateTime2 = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.FindSystemTimeZoneById(localZone.StandardName));
            return dateTime.ToString("yyyyMMddTHHmmssZ");
        }
        public String Ahorawey()
        {
            DateTime dth = DateTime.Now;
            DateTime dTime;
            dTime = TimeZoneInfo.ConvertTimeToUtc(dth, TimeZoneInfo.Local);
            return dTime.ToString("yyyyMMddTHHmmssZ");
        }
    }
    class CrearICS
    {
        public void CreameEsta(string email, string nombreinv, string nombreev, string emailor,string asunto,int ast, int mast, int dast, int hast, int mnast, int sast, int aed, int med, int ded, int hed, int mned, int sed)
        {
            Fechas f = new Fechas();
            //especifico en windows
            //string lugar = @"C:\Users\ceflor\Documents\";
            //mac y windows
            string lugar = "./evento/";
            System.IO.Directory.CreateDirectory(lugar);
            string nombre = "prueba" + DateTime.Now.ToString("ddMMyyyyss") + ".ics";
            lugar = System.IO.Path.Combine(lugar, nombre);
            using (System.IO.StreamWriter mylogs = System.IO.File.AppendText(lugar))
            {
                String ics = @"BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:"+ email +
                            "\nDTSTAMP:" + f.Ahorawey() +
                            "\nORGANIZER; CN="+nombreev+":MAILTO:"+emailor +
                            "\nDTSTART:" + f.Regresameesta(ast, mast, dast, hast, mnast, sast) +
                            "\nDTEND:" + f.Regresameesta(aed, med, ded, hed, mned, sed) +

                            "\nSUMMARY:" + asunto+
                            "\nGEO:" + "25.6534664;-100.3407974"+
                            "\nEND:VEVENT" +
                            "\nEND:VCALENDAR";
                mylogs.WriteLine(ics);
                mylogs.Close();
            }
            Console.Write("\n------------------- \n");
            email mail = new email(email, nombreinv, emailor, nombre, nombreev);
            Console.Write("correo enviado");

        }
    }

Creando nuestra función envió de correo electrónico con c# y net core

en esta función vamos a enviar el correo electrónico del invitado, pasaremos información de quien lo invita la url del evento que acabamos de crear, esto es tan personalizable como quieran.

los primeros, configuramos nuestro cliente de correo electrónico, en este caso yo uso hostinger  y me dan estos puertos para no complicarme la vida y enviar emails.

//puerto para enviar correo
            SmtpClient client = new SmtpClient("mx1.hostinger.mx", 587);
            client.EnableSsl = true;

configuramos nuestro correo que vamos a enviar y luego quien va a recibir el correo

//email que envia
            MailAddress from = new MailAddress("pruebas@unprogramador.com", "Pruebas un programador");
            MailAddress to = new MailAddress(emailInvitar, nombre);

con mailMessage configuramos quien envia y quien recibe (con formato MailAndress) y tenemos la opcion de agregar un documento, un asunto y hasta copia

MailMessage msn = new MailMessage(from, to);
            msn.Body = "Hola "+nombre+" Se te hace una invitacion para un evento departe de " + nombreOrganizador + " <" + emailOrganizador + ">" + " solo da click en el archivo con extension ics para agregarlo a tu calendario .\n gracias!";
            msn.Attachments.Add(new Attachment("./evento/"+archivo));
            msn.Subject = "Invitacion de "+nombreOrganizador+"<"+ emailOrganizador+">";
            //hago una copia
            msn.CC.Add(new MailAddress("shingrey@unprogramador.com"));

al final enviamos sin antes poner nuestras credenciales de nuestro correo que va a enviar

//credenciales
            NetworkCredential myCreds = new NetworkCredential("pruebas@unprogramador.com", "contraseña", "");
            client.Credentials = myCreds;
            try
            {

                client.Send(msn);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception is:" + ex.ToString());
            }

Este el código completo de email:

namespace crearics
{
    class email
    {
        public email(String emailInvitar, String nombre, String emailOrganizador, String archivo,String nombreOrganizador)
        {
            //puerto para enviar correo
            SmtpClient client = new SmtpClient("mx1.hostinger.mx", 587);
            client.EnableSsl = true;
            //email que envia
            MailAddress from = new MailAddress("pruebas@unprogramador.com", "Pruebas un programador");
            MailAddress to = new MailAddress(emailInvitar, nombre);
            MailMessage msn = new MailMessage(from, to);
            msn.Body = "Hola "+nombre+" Se te hace una invitacion para un evento departe de " + nombreOrganizador + " <" + emailOrganizador + ">" + " solo da click en el archivo con extension ics para agregarlo a tu calendario .\n gracias!";
            msn.Attachments.Add(new Attachment("./evento/"+archivo));
            msn.Subject = "Invitacion de "+nombreOrganizador+"<"+ emailOrganizador+">";
            //hago una copia
            msn.CC.Add(new MailAddress("shingrey@unprogramador.com"));
            //credenciales
            NetworkCredential myCreds = new NetworkCredential("pruebas@unprogramador.com", "contraseña", "");
            client.Credentials = myCreds;
            try
            {

                client.Send(msn);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception is:" + ex.ToString());
            }
        }

    }
}

el resultado es el siguiente

crear un evento en calendario

y lo recibimos de la siguiente manera

crear un evento en calendario

esto lo podemos visualizar en cualquier smarthphone y como ven, el código lo comencé a hacer en windows 10 y lo termine y compile en una mac.

Les dejo la url de mi repositorio:

Repositorio de Cesar Flores (shingrey) – crearics

por Cesar Flores

Programador de tiempo completo, Gamer de medio tiempo y fotógrafo ocasionalmente, me gusta el front-end y mi framework favorito es angular aunque no por eso le hago el feo a un nuevo lenguaje.

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.