DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • How To Manage Vulnerabilities in Modern Cloud-Native Applications
  • How To Scan and Validate Image Uploads in Java
  • Application Architecture Design Principles
  • Integrating AWS With Salesforce Using Terraform

Trending

  • How To Manage Vulnerabilities in Modern Cloud-Native Applications
  • How To Scan and Validate Image Uploads in Java
  • Application Architecture Design Principles
  • Integrating AWS With Salesforce Using Terraform
  1. DZone
  2. Data Engineering
  3. Databases
  4. Creating GMail in 15 minutes with "pure Magic"

Creating GMail in 15 minutes with "pure Magic"

Watch me re-create GMail in 15 minutes using nothing but "pure Magic"

Thomas Hansen user avatar by
Thomas Hansen
CORE ·
Aug. 28, 20 · Tutorial
Like (2)
Save
Tweet
Share
6.55K Views

Join the DZone community and get the full member experience.

Join For Free

I wanted to have some more advanced use cases for Magic, so I figured what could possibly be more insulting, than me implementing GMail in 15 minutes - A software system probably dozens of developers have maintained, for some roughly 15 years? So I did it ...

The thing about GMail, or rather its core, is that fundamentally it's just a POP3 server and an SMTP server, and the ability to send and retrieve emails over these two standards. In addition to saving emails sent and received into a database. So obviously, we'll need a database. Check!

MySQL
 




xxxxxxxxxx
1
28


 
1
create database magic_mail;
2
use magic_mail;
3

          
4
create table emails (
5
  id int(11) not null auto_increment,
6
  subject varchar(2048) null,
7
  body text null,
8
  direction varchar(20) not null,
9
  primary key (id)
10
);
11

          
12
create table contacts (
13
  id int(11) not null auto_increment,
14
  email varchar(2048) null,
15
  primary key (id)
16
);
17

          
18
create table emails_contacts (
19
  email_id int(11) not null,
20
  contact_id int(11) not null,
21
  primary key (email_id, contact_id),
22
  key email_id_key (email_id),
23
  key contact_id_key (contact_id),
24
  constraint email_fky foreign key (email_id) references emails (id) on delete cascade,
25
  constraint contact_fky foreign key (contact_id) references contacts (id) on delete cascade
26
);


Execute the above SQL script, using Magic, the same way I do in the above video, and we're all set. Of course, I'm not creating a multi user enterprise GMail system, which you can understand by the above script - But modifying the above script to become a multi user solution, could probably be done in 30 minutes or so. If you wish to try this out, you'd probably need some sort of "account settings" table, and probably you'd want to add the tables to your main magic database, and create some sort of referential integrity from your "users" table to your account settings table, in addition to your emails/contacts table(s). The above SQL script creates the following 3 tables though.

  • emails (email content)
  • contacts (people sending me emails)
  • emails_contacts (many 2 many relationship between the two above tables)

Now, if I can create a background thread, fetching emails from my POP3 server, pushing emails into the above database tables - We're already a long way, right? Check!

Plain Text
 




xxxxxxxxxx
1
26


 
1
wait.mysql.connect:magic_mail
2
   wait.mail.pop3.fetch
3
      .lambda
4
         unwrap:x:+/*
5
         .content
6
            from:x:@.message/*/from/0
7
            subject:x:@.message/*/subject
8
            body:x:@.message/**/entity/**/content/[0,1]
9
         .sender-id
10
         wait.set-value:x:@.sender-id
11
            wait.mysql.scalar:select id from contacts where email = @email
12
               @email:x:@.content/*/from
13
         wait.if
14
            eq
15
               get-value:x:@.sender-id
16
               .
17
            .lambda
18
               wait.set-value:x:@.sender-id
19
                  wait.mysql.scalar:insert into contacts (email) values (@email); select last_insert_id();
20
                     @email:x:@.content/*/from
21
         wait.mysql.scalar:insert into emails (subject, body, direction) values (@subject, @body, 'received'); select last_insert_id();
22
            @subject:x:@.content/*/subject
23
            @body:x:@.content/*/body
24
         wait.mysql.execute:insert into emails_contacts (email_id, contact_id) values (@email, @contact)
25
            @email:x:@wait.mysql.scalar
26
            @contact:x:@.sender-id


The above is the Hyperlambda we wrap into a scheduled task in the video, which is periodically polling emails from my POP3 server every 5 seconds. It basically just polls emails from my POP3 server, and insert emails into the emails table, and the sender's email address into my contacts table. In addition, it creates an association between the contacts and the emails table for me. It's important you create a scheduled task containing the above Hyperlambda though. You can see a screenshot of how below.

In addition we'll need to configure our SMTP and POP3 server settings, right? Check!

JSON
 




xxxxxxxxxx
1
23


 
1
    "smtp":{
2
      "host":"smtp.gmail.com",
3
      "port":465,
4
      "secure":true,
5
      "username":"testing.anarchy@gmail.com",
6
      "password":"ThisIsARubbishPassword",
7
      "from": {
8
        "name":"Testing Anarchy",
9
        "address":"testing.anarchy@gmail.com"
10
      }
11
    },
12
    "pop3":{
13
      "host":"pop.gmail.com",
14
      "port":995,
15
      "secure":true,
16
      "username":"testing.anarchy@gmail.com",
17
      "password":"ThisIsARubbishPassword",
18
      "from": {
19
        "name":"Testing “Anarchy",
20
        "address":"testing.anarchy”@gmail.com"
21
      }
22
    },


Stuff the above into your appsettings.json file, and you have configured your POP3 and SMTP settings. Notice, you'll have to exchange the actual POP3/SMTP settings, but if you're using GMail for POP3 and SMTP, all you have to do is to exchange your username and password. And yes, I did change my own GMail password ... ;)

In addition you'll need to grant access to your GMail account using POP3, which you can see how to do in the above video. Make sure you also open your GMail account for "insecure apps", which is a really bad name for allowing direct POP3 and SMTP access may I add. The only thing remaining is to create a secured HTTP REST endpoint for actually being able to send emails, which you can see the code for below, and we're almost completely done.

Plain Text
 




xxxxxxxxxx
1
14


 
1
.arguments
2
   to:string
3
   subject:string
4
   body:string
5
auth.ticket.verify:root
6
unwrap:x:+/**
7
wait.mail.smtp.send
8
   message
9
      to
10
         :x:@.arguments/*/to
11
      subject:x:@.arguments/*/subject
12
      entity:text/plain
13
         content:x:@.arguments/*/body
14

          


The above code, is the Hyperlambda I put into my "modules/magic_mail/send-email.post.hl" file in the above video. Now we can scaffold our app, which ends up looking roughly like this once we're done.

Notice, the only change I actually applied to the scaffolded app, was to slightly modify its "edit.emails.component.ts" file. The change I applied, was the following TypeScript code.

TypeScript
 




xxxxxxxxxx
1
16


 
1
  public close(data: any) {
2
    if (data) {
3
      this.service.send_email_Post({
4
        to: this.recipient,
5
        subject: data.subject,
6
        body: data.body
7
      }).subscribe(res => {
8
        this.dialogRef.close(data);
9
      }, error => {
10
        this.snackBar.open(error.error.message, 'ok');
11
      });
12
    } else {
13
      this.dialogRef.close();
14
    }
15
  }
16

          


Then I slightly modified the HTML to become the following.

HTML
 




xxxxxxxxxx
1
44


 
1
  <mat-form-field
2
    class="entity-edit-field-full">
3
    <input
4
      matInput
5
      placeholder="Recipient"
6
      [(ngModel)]="recipient"
7
      autocomplete="off">
8
  </mat-form-field>
9

          
10
  <mat-form-field
11
    *ngIf="canEditColumn('subject')"
12
    class="entity-edit-field-full">
13
    <input
14
      matInput
15
      type="text"
16
      placeholder="subject"
17
      [(ngModel)]="data.entity.subject"
18
      autocomplete="off">
19
  </mat-form-field>
20

          
21
  <mat-form-field
22
    *ngIf="canEditColumn('body')"
23
    class="entity-edit-field-full">
24
    <textarea
25
      matInput
26
      rows="10"
27
      type="text"
28
      placeholder="body"
29
      [(ngModel)]="data.entity.body"
30
      autocomplete="off">
31
    </textarea>
32
  </mat-form-field>
33

          
34
  <mat-form-field
35
    *ngIf="canEditColumn('direction')"
36
    class="entity-edit-field-hidden">
37
    <input
38
      matInput
39
      type="text"
40
      placeholder="direction"
41
      [(ngModel)]="data.entity.direction"
42
      autocomplete="off">
43
  </mat-form-field>
44

          


And then I modified its scss file to become the following.

SCSS
 




xxxxxxxxxx
1


 
1
 .entity-edit-field-full {
2
     width: 100%;
3
 }
4

          
5
 .entity-edit-field-hidden {
6
     display: none;
7
 }


And we're done. Basically, 80% of the (most important) features from GMail, allowing you to retrieve, send, and read emails, in an Angular + .Net Core Web application.

Insulting GMail's developers - Check!

Gmail Database

Opinions expressed by DZone contributors are their own.

Trending

  • How To Manage Vulnerabilities in Modern Cloud-Native Applications
  • How To Scan and Validate Image Uploads in Java
  • Application Architecture Design Principles
  • Integrating AWS With Salesforce Using Terraform

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: